小目标7 上传文件功能

发布时间 2023-10-09 09:34:39作者: †CS.Renascence

这次我们要实现的功能是按3,客户端把指定文件夹下的文件传到服务器上

 

客户端和服务器都增加上传文件的宏定义

 #define MSG_TYPE_UPLOAD   3

 

修改客户端case3的部分

up_file_name是要上传的文件名

 char up_file_name[20] = { 0 };//定义为全局变量
 ​
 //下面是修改后客户端的代码
 case '3':
     send_msg.type = MSG_TYPE_UPLOAD;
     printf("input upload filename:");
     puts(up_file_name);
     //在上传文件给服务器之前,你要先发送一个数据包给服务器,告诉服务器我这边准备上传文件了
     strcpy(send_msg.fname, up_file_name);
     res = write(client_socket, &send_msg, sizeof(MSG));
     if (res < 0)
     {
         perror("send upload package error:");
         continue;
     }
     memset(&send_msg, 0, sizeof(MSG));

 

 

服务器部分的线程函数要增加一个判断,如果type是上传,就读从客户端发来的数据,然后创建文件夹

也要定义:char up_file_name[20]

 else if (recv_msg.type == MSG_TYPE_UPLOAD) //如果收到的是上传包,说明准备接收客户端发来的文件数据了
 {
     //要从数据包的文件名里面获取文件名信息,然后创建文件。默认创建的文件夹是在家目录下
     strcpy(up_file_name, recv_msg.fname);
     //然后在家目录下创建文件
     
     fd = open("/home/liujiajun/css.txt", O_CREAT | O_WRONLY, 0666);
     if (fd < 0)
     {
         perror("create up file error:");
     }
 }

 

客户端因为发送文件需要比较长的时间,如果在case3里面写传输文件的代码就可能会寄,所以我们再创建一个新的线程来专门处理文件上传任务,然后在客户端里面写一个上传文件的线程函数。修改后的代码如下

 //上传文件函数
 void* upload_file_thread(void* arg) {
 ​
 }
 ​
 //case3部分:
 case '3':
     send_msg.type = MSG_TYPE_UPLOAD;
     printf("input upload filename:");
     puts(up_file_name);
     //在上传文件给服务器之前,你要先发送一个数据包给服务器,告诉服务器我这边准备上传文件了
     strcpy(send_msg.fname, up_file_name);
     res = write(client_socket, &send_msg, sizeof(MSG));
     if (res < 0)
     {
         perror("send upload package error:");
         continue;
     }
     memset(&send_msg, 0, sizeof(MSG));
     pthread_create(&thread_send_id, NULL, upload_file_thread, &client_socket);
     break;
     //由于考虑到上传文件是需要比较长的时间,考虑到如果文件很大,那么就需要非常长的时间,这个时候如果写
     // //在这里那么久卡诺导致其他功能卡住排队等待,因此需要把发送文件内容的代码放进线程里面,因此需要创建线程
     // //还需要创建一个新的线程,来专门处理文件上传任务

 

当前代码执行后在Ubantu的主目录下会多一个名为css.txt的文件,说明服务器创建文件成功

image-20231008194557773

 

 

 

真正上传数据的时候还需要一个宏定义(服务器和客户端都要)

 #define MSG_TYPE_UPLOAD_DATA    4

 

接下来我们开始写客户端上传文件的线程函数

 void* upload_file_thread(void* args)
 {
 // 客户端实现长传文件到服务器的逻辑思路
     //1 肯定是要打开文件
     MSG up_file_msg = { 0 };
     char buffer[1024] = { 0 }; // 用来保存读取文件的数据缓冲区
     int client_socket = *((int*)args);
     int res = 0;
     int fd = -1;
     fd = open("./download/css/txt", O_RDONLY);
     if (fd < 0)
     {
         perror("open up file error : ");
         return NULL;
     }
    
     up_file_msg.type = MSG_TYPE_UPLOAD_DATA;
     while ((res = read(fd, buffer, sizeof(buffer))) > 0)
     {
         // 要把文件数据内容拷贝到 MSG 结构体中的 buffer 中
         memcpy(up_file_msg.buffer, buffer, res);
         up_file_msg.bytes = res;
         res = write(client_socket, &up_file_msg, sizeof(MSG));
         memset(buffer, 0, sizeof(buffer));
         memset(up_file_msg.buffer, 0, sizeof(up_file_msg.buffer));
     }
     close(fd);
 }

 

然后再服务器的线程函数里面再加一个判断

 else if (recv_msg.type == MSG_TYPE_UPLOAD_DATA)
 {
     //写的字节数是recv_msg.bytes
     write(fd, recv_msg.buffer, recv_msg.bytes);
     if (recv_msg.bytes < sizeof(recv_msg.buffer))
     {
         printf("client uploaded file: %s\n", up_file_name);
         close(fd);
     }
     memset(&recv_msg, 0, sizeof(MSG));
 }

 

以上代码执行完之后,在客户端的本地文件夹下面的css.txt中的内容将会被复制到home/liujiajun目录下的css.txt中