C 套接字在同一请求中上传和下载文件



我正在尝试接收客户端上传的文件,并且在同一套接字描述符中发送命令 以块的形式从服务器下载文件

问题是如果套接字描述符在不同的文件中,事情可以完美运行,但如果它是相同的文件客户端和服务器程序会挂起

第二个问题是,即使它在不同的文件中,我也无法向客户端发送一条消息,说文件已收到

任何人都可以提供建议

PS-要运行程序可能需要创建一个名为fileclient的文件.txt并输入一些随机文本

服务器.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#define PORT 8088
int main(void){   
int fd =0, confd = 0,b,tot;
struct sockaddr_in serv_addr;
char buff[1025];
fd = socket(AF_INET, SOCK_STREAM, 0);
printf("Socket createdn");
memset(&serv_addr, '0', sizeof(serv_addr));
memset(buff, '0', sizeof(buff));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
serv_addr.sin_port = htons(PORT);
bind(fd, (struct sockaddr*)&serv_addr, sizeof(serv_addr));
listen(fd, 10);
while(1){
confd = accept(fd, (struct sockaddr*)NULL, NULL);
if (confd==-1) {
perror("Accept");
continue;
}
//READ COMMAND reads first 4 characters of the buffer
int bf = recv(confd, buff, 1024,0);
char *filecmd = malloc(5 * sizeof(char));
memcpy(filecmd, buff, 4);
filecmd[4] = 0; //string termination 
//if command is DOWN send chunks to the client 
if(strcmp(filecmd, "DOWN") == 0){
int bt;
char sendbuffer[100];
FILE *fpdl = fopen("file.txt", "rb");
if(fpdl == NULL){
perror("File");
return 2;
}
while( (bt = fread(sendbuffer, 1, sizeof(sendbuffer), fpdl))>0 ){
send(confd, sendbuffer, bt, 0);
}
fclose(fpdl);
}
//if DOWN did not match that means client is uploading a file write down the file on server
else{           
FILE* fp = fopen( "newfile.txt", "wb");
tot=0;
tot+=bf;
fwrite(buff, 1, bf, fp);
if(fp != NULL){
while( (b = recv(confd, buff, 1024,0))> 0 ) {                   
tot+=b;
fwrite(buff, 1, b, fp);
}
printf("Received byte: %dn",tot);
if (b<0) perror("Receiving Error");
fclose(fp);
} else {
perror("File");
}
}
free(filecmd);
close(confd);
}
return 0;
}

客户端.c

#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <arpa/inet.h>
#define PORT 8088

int main(int argc, char *argv[]){
int sfd =0, n=0, b;
char sendbuffer[100];
struct sockaddr_in serv_addr;
sfd = socket(AF_INET, SOCK_STREAM, 0);
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
serv_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
b=connect(sfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
if (b==-1) {
perror("Connect");
return 1;
}
FILE *fp = fopen("fileclient.txt", "rb");
if(fp == NULL){
perror("File");
return 2;
}
while( (b = fread(sendbuffer, 1, sizeof(sendbuffer), fp))>0 ){
send(sfd, sendbuffer, b, 0);
}
fclose(fp);

char *rpccommand = "DOWN"; 
send(sfd , rpccommand , strlen(rpccommand) , 0 ); 
char buffer[1024] = {0}; 
FILE* fpx = fopen( "downloadfile.txt", "wb");
int tot=0, bn;
if(fpx != NULL){
while( (bn = recv(sfd, buffer, 1024,0))> 0 ) {
tot+=bn;
fwrite(buffer, 1, bn, fpx);
}
printf("Received byte: %dn",tot);
if (bn<0) perror("Receiving");
fclose(fpx);
} else {
perror("File");
}
return 0; 
}

您似乎希望服务器识别字符串"DOWN"并触发下载。这不太可能发生。

TCP 连接不关心放入套接字的数据的粒度。如果您在一侧一次输入 1000 个字节,则不能保证一次性接收这 1000 个字节。 您可能会收到 1000 字节或 500 + 500 字节的 999 + 1 字节。

如果您发送多个请求,则同样适用。输入 1000+4 字节可能会导致接收 1000+4 或 1004 或 500+500+4 字节或任何其他组合。

这意味着您不能简单地依靠先接收文件上传的所有字节,然后等待另一个命令("DOWN"(或其他文件。您很可能会收到"DOWN"以及上传文件的最后字节,并简单地将它们存储到输出文件中。

这同样适用于下载方向。客户端将无法区分文件下载和"上载完成"通知。

为了解决您的问题,您需要在协议中引入更多逻辑。有多种选择:

每个
  • 操作或每个方向使用 1 个插座和 1 个连接。无需将所有内容混合到单个插槽中。
  • 添加一些关于文件上传的指示,例如上传前的预期总长度。
  • 使用 1 个套接字
  • 进行控制流,使用多个其他套接字进行数据传输(有关详细信息,请参阅 FTP(

最新更新