服务器写入套接字但数据未到达客户端

时间:2011-11-30 00:29:46

标签: c linux sockets

我正在为我的网络类编写一个简单的服务器,我无法正确地将数据传输到客户端(由教授提供)。

一旦完成所有设置并建立连接,我就开始读取文件的块并将它们写入套接字检查以查看读写函数的返回是否匹配。我还保持读取/写入的字节总数,并将其与总文件大小进行比较(通过stat.st_size),它们都匹配。

无论我多少次请求同一个文件,服务器端的日志始终都有正确的指标。客户端偶尔会丢失文件的末尾。从一次调用到下一次调用,实际大小和预期大小之间的差异几乎从来没有相同,看起来总是缺少文件的末尾,中间没有任何碎片。到达文件的大小也是512的倍数(块大小)。

所以,似乎有一些完整的块正在制造它,然后其余的都会以某种方式迷失。:

#define CHUNK_SIZE     512
/* other definitions */

int main()
{
   /* basic server setup: socket(), bind(), listen() ...  
      variable declarations and other setup  */

   while(1)
   {
      int cliSock = accept(srvSock, NULL, NULL);
      if(cliSock < 0)
         ; /* handle error */

      read(cliSock, filename, FILE_NAME_SIZE - 1);
      int reqFile = open(filename, O_RDONLY);
      if( reqFile == -1)
         ; /* handle error */

      struct stat fileStat;
      fstat(reqFile, &fileStat);
      int fileSize = fileStat.st_size;

      int bytesRead, totalBytesRead = 0;
      char chunk[CHUNK_SIZE];
      while((bytesRead = read(reqFile, chunk, CHUNK_SIZE)) > 0)
      {
         totalBytesRead += byteasRead;
         if(write(cliSock, chunk, bytesRead) != bytesRead)
         {
            /* perror(...) */
            /* print an error to the log file */
            bytesRead = -1;
            break;
         }
      }
      if (bytesRead == -1)
      {
         /* perror(...) */
         /* print an error to the log file */
         close(cliSock);
         continue;
      }

      /* more code to write transfer metrics etc to the log file */
   }
}

所有删除的错误处理代码都是将错误消息打印到日志文件并返回循环顶部的一种风格。


编辑翻转了应该<

>

1 个答案:

答案 0 :(得分:2)

当您将所需的所有数据写入套接字(或者可能只是退出进程,执行相同的操作)时,您可能会毫不客气地使用close()关闭套接字。

这不对 - 如果另一方发送了一些你没有读过 1 的数据,连接将被重置。重置可能导致未读数据丢失。

相反,您应该使用shutdown()正常关闭套接字的写入端,然后等待客户端关闭。类似的东西:

ssize_t bytesRead;
char chunk[CHUNK_SIZE];

shutdown(cliSock, SHUT_WR);

while((bytesRead = read(cliSock, chunk, CHUNK_SIZE)) != 0)
{
    if (bytesRead < 0)
    {
        if (errno != EINTR)
        {
            /* perror() */
            /* print error in log file */
            break;
        }
    }
    else
    {
        /* maybe log data from client */
    }
}

close(cliSock);

<小时/> 1。这可以包括EOF,如果另一方已关闭其写入通道。