文章目录
- 下载:
- 下载的过程:
- 单文件传输:
- 多文件传输:
下载:
如下图:
- 如果刚发完size,客户端不回复ok,直接发送数据,会出现粘包问题。
- 如果想要确保客户端收到数据,可以每发送一个数据,客户端回复一个ok。
下载的过程:
单文件传输:
- 客户端发送 get a.c 给服务器
- 服务器查看其目录中是否a.c文件
- 如果有,回复ok,并将a.c文件的大小发送给客户端。(用来提示客户端什么时候下载完),否则回复error (名字错误,没有找到等等错误)
- 客户端收到服务器的确认,并回复服务器ok。
- 服务器开始发送数据。(一次或多次)
多文件传输:
- 客户端发送 get a.c b.c给服务器
- 服务器查看其目录中是否a.c b.c文件
- 如果有,回复ok。
- 客户端收到服务器的确认,创建2个链接,专门负责a.c 和b.c文件的传输,并回复服务器ok。(直到链接关闭,说明文件传输完了)
- 服务器开始发送数据。(一次或多次)
lseek:获取文案描述符的偏移量(文件大小)
服务器 thread.c
void send_file(int c,char *filename)
{
if(filename == NULL)
{
send(c,CMD_ERR,strlen(CMD_ERR),0);
return;
}
int fd = open(filename,O_RDONLY);
if(fd == -1)
{
send(c,FILE_ERR,strlen(FILE_ERR),0);
return;
}
//lseek,将文件的偏移量指针末尾
int filesize = lseek(fd,0,SEEK_END);
lseek(fd,0,SEEK_SET);
//将文件偏移指针移动到文件开始
char buff_size[64] = {0};
sprintf(buff_size,"ok#%d",filesize);
send(c,buff_size,strlen(buff_size),0);
//发送文件大小
memset(buff_size,0,64);
int n = recv(c,buff_size,63,0);
if ( n <= 0 )
{
return;
}
if ( strcmp(buff_size,"err") == 0 )
{
return;
}
char data[1024];
int num = 0;
//读取文件内容
while( (num = read(fd,data,1024)) > 0 )
{
send(c,data,num,0);
}
close(fd);
return;
}
客户端:
//cmd_buff : get a.c
void recv_file(int c, char cmd_buff[], char* filename)
{
if(cmd_buff == NULL || filename == NULL)
{
return;
}
send(c,cmd_buff,strlen(cmd_buff),0);
char buff[64] = {0};
int num = recv(c,buff,63,0);
if(num <= 0)
{
printf("ser close or err\n");
return;
}
//ok#size ,有数据就可以写数据
int filesize = 0;
sscanf(buff+3,"%d",&filesize);
printf("文件:%s,大小:%d\n",filename,filesize);
if ( filesize < 0 )
{
send(c,"err",3,0);
return;
}
int fd = open(filename,O_CREAT|O_WRONLY,0600);
if ( fd == -1 )
{
printf("创建文件失败\n");
send(c,"err",3,0);
return;
}
send(c,"ok",2,0);
char data[1024];
int curr_size = 0;
while( 1 )
{
int n = recv(c,data,1024,0);
if ( n <= 0 )
{
printf("down file err\n");
break;
}
write(fd,data,n);
curr_size += n;
float f = curr_size * 100.0 / filesize;
printf("当前下载:%.2f%%\r",f);
fflush(stdout);
if ( curr_size >= filesize )
{
break;
}
}
close(fd);
printf("\n");
printf("文件下载完成\n");
return ;
}