【问题标题】:Binary file transfer over Socket using TCP使用 TCP 通过 Socket 传输二进制文件
【发布时间】:2012-02-07 12:09:53
【问题描述】:

我正在开发一个二进制文件传输程序,其中客户端必须将文件上传到服务器。对于这种情况,我需要先发送文件名,然后再发送文件内容。但这对我来说是不可行的。

让我们看看代码:

// Client-side code to send file name
void sendFileName(
    int sd,         /*Socket Descriptor*/
    char *fname)    /*Array Containing the file name */
{       
    int n , byteswritten=0 , written ;
    char buffer[1024];
    strcpy(buffer , fname);
    n=strlen(buffer);
    while (byteswritten<n)
    {
        written=write(sd , buffer+byteswritten,(n-byteswritten));
        byteswritten+=written;
    }
    printf("File name : %s sent to server \n",buffer);
}

在这段代码中,我通过套接字写入文件名,服务器将从套接字读取名称,如下所示:

// Server-side code to read file name from client
while ((n = read((int)connfd, (fname + pointer), 1024)) > 0)
{
    pointer=pointer+n;
}

好吧,问题是我必须在发送文件名后关闭客户端的写入端,这将是服务器端代码停止从服务器读取的 FIN 段。

如果我像这样关闭读取端:

shutdown(sd,SHUT_WR);       //Closing write end at client side

如何通过套接字将文件内容写入(即发送)到服务器,以便它可以从套接字读取?

注意:我所做的是将文件名附加到来自客户端的文件内容,并在内容中添加一个特殊字符(用于通知文件名结束),然后是文件内容。

在客户端,

void readWriteFile(
   int sd,                      /*Socket Descriptor */
   int fd,                      /*File Descriptot */
   char *fname)                 /*File Name  */
{
   char buffer[1050];
   int n;
   int len = 0;
   char *tmp = (char *)malloc(sizeof (char) * (strlen(fname) + 2));
   strcpy(tmp, fname);          //Copying the file name with tmp 
   strcat(tmp, "/");            //Appending '/' to tmp
   len = strlen(tmp);
   memset(buffer, '\0', sizeof (buffer));
   strcpy(buffer, tmp);         //Now copying the tmp value to buffer

   while ((n = read(fd, buffer + len, 1024)) > 0)
   {
      if (write(sd, buffer, n) != n)
      {
         printf("File write Error \n");
         exit(0);
      }
      len = 0;
   }
   printf("File sent successfully \n");
}

在服务器端,

   char fname[50], buffer[1024];
   int n, fd;
   int i;
   int start = 0;

   while ((n = read((int)connfd, buffer, 1024)) > 0) // Reading from socket
   {
      if (!start)
      {
          /* This 'if' loop will executed almost once i.e. until 
             getting the file name */
         for (i = 0; i < 1024; i++)
         {
            /* Since '/' is the termination character for file name */
            if (buffer[i] == '/')
            {
               start = 1;       // Got the file name
               break;
            }

            fname[i] = buffer[i]; //Storing the file name in fname
         }

         fname[i] = '\0';

         /* Creating the file in the server side */
         fd = open(fname, O_WRONLY | O_CREAT, S_IRWXU);

         if (fd < 0)
         {
            perror("File error");
            exit(0);
         }

         /* Here writing the buffer content to the file after 
            the (buffer+i+1), because after this address only, we 
            can get the original file content */

         write(fd, buffer + i + 1, n);
      }
      else
      {
         write(fd, buffer, n);
      }
   }
   printf("%s received successful \n", fname);

此代码适用于图像、可执行文件和文本文件。但是,如果我发送任何音频文件,它就不会在服务器端播放。大小仍然是大小。但我想知道为什么音频文件会发生这种情况。逻辑有什么问题吗?我还没有试用视频文件。

【问题讨论】:

  • 注意written的返回值在非常普通的情况下可能是-l,例如errnoEGAINEINTR。这会给你的逻辑带来麻烦。
  • “但这对我来说不可行。”如果它不可行,为什么还要问呢?听起来你已经放弃了。

标签: c sockets client-server shutdown file-transfer


【解决方案1】:

为什么说“发送文件名后我必须在客户端关闭写端”?您还没有完成发送数据,所以您肯定还不想关闭套接字吗?

首先决定您希望如何构建数据,以便接收器可以读取它并重建原始文件名和文件内容。您可能希望如何构建它的一些示例:

  • 发送文件名,以 NUL 字节结束,然后发送内容。
  • 以网络字节顺序(大端)发送两个 32 位整数,分别包含文件名的长度和文件内容的长度。然后发送文件名,然后是文件内容。
  • 将文件名和文件内容序列化为结构化文档格式,如 JSON 或 XML。发送序列化版本。 (对于您的用例来说,这可能有点矫枉过正。)

在发送完整个结构后关闭套接字,无论你决定它是什么。

通过这些安排中的任何一种,接收器都拥有明确重建原始文件名和内容所需的所有信息。

更新:您在问题中添加了更多内容,这几乎是一个不同的问题...

您的服务器端代码(读取文件名和文件内容的代码)包含许多错误。

  • 您假设文件名将在第一个缓冲区数据中完全传送。如果您在没有找到文件名终止符的情况下耗尽了该缓冲区,那么您的代码就会到处乱跑(它会打开一个不正确的文件,它会写入一些垃圾,当读取下一个缓冲区时,它会从头开始再次查找文件名)。
  • 您将n 字节从第一个缓冲区数据写入输出文件,即使没有n 字节可用。实际上有 n 减号,但文件名使用了很多。
  • 您不会对 read()write() 进行任何错误检查,但为了清楚问题,我假设您省略了这一点...
  • 您不检查另一端提供的文件名是否超过您的 50 字节缓冲区。

在其他大小的代码中,存在明显的缓冲区溢出,您将 1024 字节读入只有 1024 - len 字节可用的缓冲区。

您需要先解决所有这些问题,然后才能期待任何工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-08
    • 2014-04-15
    • 1970-01-01
    • 2011-08-27
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多