【问题标题】:C Sending files with Berkeley socketC 使用 Berkeley 套接字发送文件
【发布时间】:2015-01-06 07:13:01
【问题描述】:

我正在尝试在用 c 编写的客户端-服务器应用程序上发送文件。

客户端应该上传文件,服务器应该接收文件。 客户端:

if(fstat(fd,&file_stat) < 0){
    perror("Fstat error");
    return -1;
}


FILE *filepointer = fopen(filename,"rb");

if(filepointer == NULL){
    perror("Opening file error");
    return -1;
}

strcat(sendbuf,"8"); // option number
strcat(sendbuf,client_account.user); //user who is sending a file
strcat(sendbuf,"p1.txt"); // file name
printf("sendbuf : %s\n",sendbuf );
if(write(sock_fd,sendbuf,strlen(sendbuf)) < 0 ){
    perror("Writing error");
    return -1;
}

/* Check server's answer */
if((nread = read(sock_fd,buffer,sizeof(buffer))) < 0){
    perror("Reading error");
    return -1;
}
buffer[nread] = '\0';
printf("Buffer : %s : %d",buffer,atoi(buffer));
if(atoi(buffer) != GENERIC_OK){
    printf("Error occurred\n");
    return -1;
}

sprintf(file_size,"%lld",file_stat.st_size);

/* Writing file size */
if((nwritten = write(sock_fd,file_size,sizeof(file_size))) < 0){
    perror("Writing error");
    return -1;
}

memset(buffer,0,sizeof(buffer));
/* Check second server's answer */
if((nread = read(sock_fd,buffer,sizeof(buffer))) < 0){
    perror("Reading error");
    return -1;
}
buffer[nread] = '\0';
printf("Buffer : %s : %d",buffer,atoi(buffer));
if(atoi(buffer) != GENERIC_OK){
    printf("Error occurred\n");
    return -1;
}


while(1){

    nbytes = fread(sendbuf,1,sizeof(sendbuf),filepointer);
    /* There are bytes to send */
    printf("Sendbuf : %s \n" , sendbuf);
    if(nbytes > 0){
        write(sock_fd,sendbuf,nbytes);
    }

    if(nbytes < 256){
        if(feof(filepointer) || ferror(filepointer))
            break;
    }
}

服务器端:

... first buffer is received well ...`
/* WRITE TO CLIENT TO CONTINUE */
if(write(sock_fd,"500",strlen("500")) < 0){ /*GENERIC OK*/
    perror("Writing error");
    return -1;
}

memset(recvBuf,0,sizeof(recvBuf));
/*RECEIVING FILE SIZE */
if((nread = read(sock_fd,buffer,sizeof(buffer)))< 0){
    perror("Reading error");
    return -1;
}
buffer[nread] = '\0';

file_size = atoi(buffer);
printf("file size : %d\n",file_size);



if((fd = open(filename, O_CREAT | O_RDWR | O_TRUNC,  S_IRWXU)) < 0){
    perror("File opening error"); /* file already exists */

}

recv_file = fopen(filename,"wb");
if(recv_file == NULL){
    perror("Opening error");
    return -1;
}

remaining_data = file_size;/*i think processes are blocking on while loops*/
while(((nread = read(sock_fd,recvBuf,sizeof(recvBuf))) > 0) && remaining_data > 0){ 
    recvBuf[nread] = '\0';
    printf("%d bytes received : %s \n",nread,recvBuf);
    fwrite(recvBuf,1,nread,recv_file);
    remaining_data -= nread;
}

if(nread < 0){
    perror("Reading error");
}

我尝试使用 sendfile 函数,但我使用的是 Mac OS 并且不受支持。你对我有什么建议吗?

应该是这样的:

1) 客户端向服务器发送一个缓冲区,宣布它将发送一个带有其名称的文件 - OK

2) 服务器接收到这个缓冲区并向客户端发送一个通用的 ok 代码 - OK

3) 客户端向服务器发送文件的大小 - OK

4) 服务器接收到这个缓冲区并向客户端发送一个通用的 ok 代码 - OK

5) 客户端从文件中读取内容并将其发送到服务器 - 不行

6) 服务器从客户端接收内容并将内容写入文件 - 不正常

【问题讨论】:

  • 也许您可以更具体地了解程序的行为不端?
  • 混合使用 POSIX I/O(read() 和 write())和标准流 I/O 函数(fread() 和 fwrite())有点奇怪,但是作为只要您对使用哪个文件保持一致,那不应该是一个实际问题。不过,我自己会一直使用 POSIX I/O。
  • @JohnBollinger 它在 while 循环中阻塞......客户端应该将充满东西的缓冲区发送到服务器,但它似乎没有发生,因为服务器被阻塞(我认为在读取功能上) 也是。
  • 代码需要在调用 strcat() 之前将 sendbuf[] 清除为所有 '\0' 并使接收方更容易解析数据,或者 sendbuf 需要是一个结构并将数据放入每个字段或在每个字段之间放置一些分隔符(如“,”或“:”)
  • 这一行,在客户端:'if(nbytes

标签: c sockets networking


【解决方案1】:

这一行,在服务器中,

while(((nread = read(sock_fd,recvBuf,sizeof(recvBuf))) > 0) && remaining_data > 0){

正在尝试先阅读,但没有检查 remaining_data &gt;0。结果是传输完所有文件后的读取操作。

建议使用while(remaining_data&gt;0) { select()/read() },其中select()有合理的超时参数,超时时会导致循环退出。

【讨论】:

    【解决方案2】:

    这段代码:

    if((fd = open(filename, O_CREAT | O_RDWR | O_TRUNC,  S_IRWXU)) < 0){
        perror("File opening error"); /* file already exists */
    
    }
    
    recv_file = fopen(filename,"wb");
    if(recv_file == NULL){
        perror("Opening error");
        return -1;
    }
    

    在服务器中打开输出文件两次,没有干预close()。这可能不是我们所需要的。

    【讨论】:

      【解决方案3】:

      我认为您遗漏了一些相关代码,但很可能关键问题在于服务器的while 条件:

      while(((nread = read(sock_fd,recvBuf,sizeof(recvBuf))) > 0) && remaining_data > 0){
      

      请注意,它会总是尝试读取数据,即使它已经读取了预期的字节数。如果客户端保持连接打开(可能它正在等待来自服务器的响应),则不会检测到 EOF 条件,并且您会遇到死锁。

      交换条件的顺序应该可以解决这个问题,至少对于表现良好的客户而言。但是请注意,即使进行了更改,如果客户端发送的字节数少于其承诺的字节数,但仍保持连接打开,您仍然可能会遇到死锁。 恶意客户端可能会故意表现出这种行为来对您的服务器执行 DoS。

      【讨论】:

        【解决方案4】:

        此外,如果完整的 'sizeof(buffer)' 字节数为收到了。

        'file_size = atoi(buffer)' - 不保证能正常工作,因为您不知道是否已收到整个缓冲区。

        同样的字节序问题。

        【讨论】:

          猜你喜欢
          • 2011-08-01
          • 1970-01-01
          • 2012-11-13
          • 2011-09-18
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-03-15
          相关资源
          最近更新 更多