c发送和接收文件

这是服务器(sendfile)部分:

offset = 0; for (size_to_send = fsize; size_to_send > 0; ){ rc = sendfile(newsockd, fd, &offset, size_to_send); if (rc <= 0){ perror("sendfile"); onexit(newsockd, sockd, fd, 3); } offset += rc; size_to_send -= rc; } close(fd); /* la chiusura del file va qui altrimenti rischio loop infinito e scrittura all'interno del file */ memset(buffer, 0, sizeof(buffer)); strcpy(buffer, "226 File Successfully transfered\n"); if(send(newsockd, buffer, strlen(buffer), 0) < 0){ perror("Errore durante l'invio 226"); onexit(newsockd, sockd, 0, 2); } memset(buffer, 0, sizeof(buffer)); 

这是客户端(recv文件)部分的一部分:

  fsize_tmp = fsize; sInfo.filebuffer = malloc(fsize); if(sInfo.filebuffer == NULL){ perror("malloc"); onexit(sockd, 0, fd, 4); } while(((uint32_t)total_bytes_read != fsize) && ((nread = read(sockd, sInfo.filebuffer, fsize_tmp)) > 0)){ if(write(fd, sInfo.filebuffer, nread) != nread){ perror("write RETR"); onexit(sockd, 0, 0, 1); } total_bytes_read += nread; fsize_tmp -= nread; } close(fd); /* la chiusura del file va qui altrimenti client entra in loop infinito e si scrive all'interno del file */ memset(buffer, 0, sizeof(buffer)); if(recv(sockd, buffer, 34, 0) < 0){ perror("Errore ricezione 226"); onexit(sockd, 0, 0, 1); } printf("%s", buffer); memset(buffer, 0, sizeof(buffer)); memset(dirpath, 0, sizeof(dirpath)); free(sInfo.filebuffer); 

问题是字符串“226 File etc etc.”已发送的文件中。
我试过做一个小调试,所以我在for循环(服务器发送文件)和while循环(客户端)之后的printf之后添加了一个printf ,我注意到该文件已发送但在客户端上不会退出,因为printf没有打印…
为什么我有这种奇怪的行为?
BR>

编辑:
服务器将文件大小发送到客户端,此代码为:

  fd = open(filename, O_RDONLY); if(fd < 0){ error!! } if(fstat(fd, &fileStat) < 0){ perror("Errore fstat"); onexit(newsockd, sockd, fd, 3); } fsize = fileStat.st_size; if(send(newsockd, &fsize, sizeof(fsize), 0) < 0){ perror("Errore durante l'invio della grandezza del file\n"); onexit(newsockd, sockd, fd, 3); } 

客户端使用以下代码从服务器接收fsize:

 if(read(sockd, &fsize, sizeof(fsize)) < 0){ perror("Errore durante ricezione grandezza file\n"); onexit(sockd, 0 ,0 ,1); } fd = open(sInfo.filename, O_CREAT | O_WRONLY, 0644); if (fd < 0) { perror("open"); onexit(sockd, 0 ,0 ,1); } fsize_tmp = fsize; 

两个fsize都声明为uint32_t

试试这段代码:

客户端:

 /* Client code */ /* TODO : Modify to meet your need */ #include  #include  #include  #include  #include  #include  #include  #include  #include  #define PORT_NUMBER 5000 #define SERVER_ADDRESS "192.168.1.7" #define FILENAME "/home/toc/foo.c" int main(int argc, char **argv) { int client_socket; ssize_t len; struct sockaddr_in remote_addr; char buffer[BUFSIZ]; int file_size; FILE *received_file; int remain_data = 0; /* Zeroing remote_addr struct */ memset(&remote_addr, 0, sizeof(remote_addr)); /* Construct remote_addr struct */ remote_addr.sin_family = AF_INET; inet_pton(AF_INET, SERVER_ADDRESS, &(remote_addr.sin_addr)); remote_addr.sin_port = htons(PORT_NUMBER); /* Create client socket */ client_socket = socket(AF_INET, SOCK_STREAM, 0); if (client_socket == -1) { fprintf(stderr, "Error creating socket --> %s\n", strerror(errno)); exit(EXIT_FAILURE); } /* Connect to the server */ if (connect(client_socket, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr)) == -1) { fprintf(stderr, "Error on connect --> %s\n", strerror(errno)); exit(EXIT_FAILURE); } /* Receiving file size */ recv(client_socket, buffer, BUFSIZ, 0); file_size = atoi(buffer); //fprintf(stdout, "\nFile size : %d\n", file_size); received_file = fopen(FILENAME, "w"); if (received_file == NULL) { fprintf(stderr, "Failed to open file foo --> %s\n", strerror(errno)); exit(EXIT_FAILURE); } remain_data = file_size; while (((len = recv(client_socket, buffer, BUFSIZ, 0)) > 0) && (remain_data > 0)) { fwrite(buffer, sizeof(char), len, received_file); remain_data -= len; fprintf(stdout, "Receive %d bytes and we hope :- %d bytes\n", len, remain_data); } fclose(received_file); close(client_socket); return 0; } 

服务器端:

 /* Server code */ /* TODO : Modify to meet your need */ #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #include  #define PORT_NUMBER 5000 #define SERVER_ADDRESS "192.168.1.7" #define FILE_TO_SEND "hello.c" int main(int argc, char **argv) { int server_socket; int peer_socket; socklen_t sock_len; ssize_t len; struct sockaddr_in server_addr; struct sockaddr_in peer_addr; int fd; int sent_bytes = 0; char file_size[256]; struct stat file_stat; int offset; int remain_data; /* Create server socket */ server_socket = socket(AF_INET, SOCK_STREAM, 0); if (server_socket == -1) { fprintf(stderr, "Error creating socket --> %s", strerror(errno)); exit(EXIT_FAILURE); } /* Zeroing server_addr struct */ memset(&server_addr, 0, sizeof(server_addr)); /* Construct server_addr struct */ server_addr.sin_family = AF_INET; inet_pton(AF_INET, SERVER_ADDRESS, &(server_addr.sin_addr)); server_addr.sin_port = htons(PORT_NUMBER); /* Bind */ if ((bind(server_socket, (struct sockaddr *)&server_addr, sizeof(struct sockaddr))) == -1) { fprintf(stderr, "Error on bind --> %s", strerror(errno)); exit(EXIT_FAILURE); } /* Listening to incoming connections */ if ((listen(server_socket, 5)) == -1) { fprintf(stderr, "Error on listen --> %s", strerror(errno)); exit(EXIT_FAILURE); } fd = open(FILE_TO_SEND, O_RDONLY); if (fd == -1) { fprintf(stderr, "Error opening file --> %s", strerror(errno)); exit(EXIT_FAILURE); } /* Get file stats */ if (fstat(fd, &file_stat) < 0) { fprintf(stderr, "Error fstat --> %s", strerror(errno)); exit(EXIT_FAILURE); } fprintf(stdout, "File Size: \n%d bytes\n", file_stat.st_size); sock_len = sizeof(struct sockaddr_in); /* Accepting incoming peers */ peer_socket = accept(server_socket, (struct sockaddr *)&peer_addr, &sock_len); if (peer_socket == -1) { fprintf(stderr, "Error on accept --> %s", strerror(errno)); exit(EXIT_FAILURE); } fprintf(stdout, "Accept peer --> %s\n", inet_ntoa(peer_addr.sin_addr)); sprintf(file_size, "%d", file_stat.st_size); /* Sending file size */ len = send(peer_socket, file_size, sizeof(file_size), 0); if (len < 0) { fprintf(stderr, "Error on sending greetings --> %s", strerror(errno)); exit(EXIT_FAILURE); } fprintf(stdout, "Server sent %d bytes for the size\n", len); offset = 0; remain_data = file_stat.st_size; /* Sending file data */ while (((sent_bytes = sendfile(peer_socket, fd, &offset, BUFSIZ)) > 0) && (remain_data > 0)) { fprintf(stdout, "1. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, offset, remain_data); remain_data -= sent_bytes; fprintf(stdout, "2. Server sent %d bytes from file's data, offset is now : %d and remaining data = %d\n", sent_bytes, offset, remain_data); } close(peer_socket); close(server_socket); return 0; } 

编辑 :添加关于offset的人的解释

send文件的手册页说:

如果offset不为NULL,则它指向一个保存文件偏移量的变量,sendfile()将从该变量开始从in_fd读取数据。
当sendfile()返回时,该变量将被设置为读取的最后一个字节之后的字节的偏移量

客户端不知道文件何时结束。 它只是读取,直到它收到fsize字节。 在您当前的实现中,客户端仅适用于精确fsize字节的文件。

我建议您更改协议并添加包含文件大小的标头。 为什么不使用http协议?

我认为你应该提供一个更详细的代码,至少使用变量声明和初始化。

客户端部分如何获得fsize值?

您还应该检查while条件,如下所示:

 while(((uint32_t)total_bytes_read < fsize) && ( ..... 

不要使用“ != ”,因为如果(由于未知原因)total_bytes_read变得大于fsize,您将被置于无限循环中,直到套接字连接关闭(并且读取返回错误)。

我也认为(但不确定)你应该在你的客户端部分使用recv而不是read

您应该始终确定要作为协议的一部分发送的文件的大小,例如,您可以在实际之前将文件大小作为前4个(或更多,取决于您希望处理的文件大小)字节发送流。

如果您希望使用常量文件,您的实现应该可以工作,在这种情况下,请为fsize和total_bytes_read添加打印。

您正在错误地使用sendfile API。 由于您在第三个参数中传入非NULL值, sendfile将为您更新偏移量。 但是因为你的发送循环也在更新偏移量,所以如果sendfile无法在一次调用中发送整个文件,你将跳过一些字节。

从手册页 :

如果offset不为NULL,则它指向一个保存文件偏移量的变量, sendfile()将从该变量开始从in_fd读取数据。 当sendfile()返回时,该变量将被设置为读取的最后一个字节之后的字节的偏移量。

您应该从发送循环中删除此行:

  offset += rc; 

编辑: 在您的更新中,您使用fpl从您的文件中获取fstat信息,但在您的sendfile代码中,您使用fd 我会确保这些是你所期望的。 (这在另一个更新中已得到修复。)无论如何,我已经使用您提供的代码(使用我建议的修复程序)编写了一个测试程序 ,并且它似乎可以正常使用少于2KB的文件和3MB的文件。