将文件从客户端传输到服务器时缺少字节,字节值也表示一些控制字符



我正在编写一个文件传输客户端/服务器应用程序其中客户端在windows7上操作,并使用vb.net编写服务器运行在linux mint上,用c++编写(我使用的是vmware)我的问题是,当我试图将文件(如图像)上传到服务器时,接收到的数据丢失了许多字节,这些字节也表示控制字符(如EOT、ETB…),我猜它们被读取为tcp控制字符,并被接收操作系统忽略。我已经用简单的文本文件(大小高达4MB)测试了这个应用程序,没有任何问题。有没有办法防止系统忽略这些字节?

这是接收文件的c++函数:

string readSockBytes(int port,int num,int size)
{
  int dcmbuffSize = 1460;
  int n;
  stringstream temp;
  string strBuffer,Sbuffer;
  char Rbuffer[dcmbuffSize];
  struct socketVar sockets;
  sockets = setSocket(port);
  sockets = sockListen(sockets);
  cout<<"user connectedn";
  strBuffer = readsock(sockets);
  cout<<strBuffer.substr(0,strBuffer.find("$"))<<endl;
  if(num == atoi(strBuffer.substr(0,strBuffer.find("$")).c_str()))
    Sbuffer = "ready$";     
  else
  {
    Sbuffer = "exit$";      
    close(sockets.newsockfd);
    close(sockets.sockfd);
  }
  n = writesock(sockets, Sbuffer, 100);
  if (n < 0) error("ERROR writing to socket");
  while(strBuffer.length() < fileSize)
  {
    n = read(sockets.newsockfd,Rbuffer,dcmbuffSize-1);
    if (n < 0) error("ERROR reading from socket");
    temp.str(Rbuffer);
    strBuffer = strBuffer+temp.str();
  }
  strBuffer = strBuffer.substr(0,size);
  return strBuffer;
}

问题很可能是您发送了二进制数据。二进制数据可以包含零。零是正常的字符串终止符。

这意味着当您执行temp.str(Rbuffer)(假设tempstd::stringstream)时,它只从Rbuffer获取数据,直到第一个零。

不使用例如std::stringstream,而是使用std::string:

while(strBuffer.length() < fileSize)
{
    char buffer[2048];
    ssize_t n = read(sockets.newsockfd, buffer, sizeof(buffer));
    if (n <= 0)
    {
        // An error, or connection closed
        if (n < 0)
            error("ERROR reading from socket");
        break;
    }
    // Create a string of `n` bytes, including possible string terminators
    // and add it to out current buffer
    strBuffer += std::string(buffer, n);
}

这里需要记住的重要一点是,不能将接收到的数据用作字符串!如果它是二进制数据,那么它肯定会包含字符串终止符,因此您必须将其视为二进制数据,而不是字符串(即使您可以将其存储在std::string中)。

您还需要注意,您不能打印数据,因为许多二进制值要么无法打印,要么将打印为"垃圾"。

最后,如果您读取和写入二进制文件,则需要以二进制模式打开它们,否则会出现字节0x0d0x0a的错误(即回车和换行)。

最新更新