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

C套接字在同一请求中上载和下载文件,c,sockets,C,Sockets,我试图接收客户端上传的文件,并在同一个套接字描述符中发送命令,从服务器分块下载文件 问题在于,如果套接字描述符位于不同的文件中,那么一切都会正常工作,但如果是同一个文件,那么客户端和服务器程序就会挂断 第二个问题是,即使它位于不同的文件中,我也无法向客户端发送一条消息,说明该文件已收到 谁能给点建议吗 PS-要运行该程序,可能需要创建一个名为fileclient.txt的文件并输入一些随机文本 服务器.c #include <stdio.h> #include <stdlib.

我试图接收客户端上传的文件,并在同一个套接字描述符中发送命令,从服务器分块下载文件

问题在于,如果套接字描述符位于不同的文件中,那么一切都会正常工作,但如果是同一个文件,那么客户端和服务器程序就会挂断

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

谁能给点建议吗

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 created\n");

    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: %d\n",tot);
                if (b<0) perror("Receiving Error");
                fclose(fp);

            } else {
                perror("File");
            }
        }
        free(filecmd);
        close(confd);
    }
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#定义端口8088
int main(void){
int fd=0,confd=0,b,tot;
服务地址中的结构sockaddr\u;
字符buff[1025];
fd=套接字(AF_INET,SOCK_STREAM,0);
printf(“已创建套接字”);
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(端口);
绑定(fd,(struct sockaddr*)&serv_addr,sizeof(serv_addr));
听(fd,10);
而(1){
confd=accept(fd,(struct sockaddr*)NULL,NULL);
如果(confd==-1){
佩罗(“接受”);
继续;
}
//READ命令读取缓冲区的前4个字符
int bf=recv(对抗,增益,1024,0);
char*filecmd=malloc(5*sizeof(char));
memcpy(filecmd,buff,4);
filecmd[4]=0;//字符串终止
//如果命令已关闭,则向客户端发送块
如果(strcmp(filecmd,“DOWN”)==0){
国际电信;
字符发送缓冲区[100];
FILE*fpdl=fopen(“FILE.txt”、“rb”);
如果(fpdl==NULL){
perror(“文件”);
返回2;
}
而((bt=fread(sendbuffer,1,sizeof(sendbuffer,fpdl))>0){
发送(confd,sendbuffer,bt,0);
}
fclose(fpdl);
}
//如果DOWN不匹配,则表示客户端正在上载文件,请在服务器上写下该文件
否则{
FILE*fp=fopen(“newfile.txt”、“wb”);
tot=0;
tot+=bf;
fwrite(buff,1,bf,fp);
如果(fp!=NULL){
而((b=recv(confd,buff,1024,0))>0){
tot+=b;
fwrite(buff,1,b,fp);
}
printf(“收到的字节:%d\n”,tot);
if(b0){
发送(sfd,发送缓冲区,b,0);
}
fclose(fp);
char*rpccommand=“向下”;
发送(sfd,rpccommand,strlen(rpccommand),0);
字符缓冲区[1024]={0};
FILE*fpx=fopen(“downloadfile.txt”、“wb”);
int-tot=0,bn;
如果(fpx!=NULL){
而((bn=recv(sfd,buffer,1024,0))>0){
tot+=bn;
fwrite(缓冲区,1,bn,fpx);
}
printf(“收到的字节:%d\n”,tot);

如果(bn您似乎期望服务器识别字符串“DOWN”并触发下载,则这种情况不太可能发生

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

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

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

下载方向也是如此。客户端将无法区分文件下载和“上载完成”通知

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

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

现在似乎是学习如何使用调试器在监视变量及其值的同时逐条检查程序语句的好时机。您知道TCP是一种没有数据报的流协议吗?服务器如何知道何时接收到整个文件?
int bf=recv(confd,buff,1024,0)
bf现在可以是-1,0,1..1024。如果bf只有
1
,你的程序会怎么做?这里有任何反馈吗?@Gerhardh很抱歉,我应该得到的响应太晚了!在客户端发送完所有命令后终止连接顺便说一句,只发送命令,将命令限制为4个字符,我的意思是“关闭”作为数据发送。字符串“DOWN”后不再添加任何数据
#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: %d\n",tot);
        if (bn<0) perror("Receiving");
        fclose(fpx);
    } else {
        perror("File");
    }
    return 0; 
}