missing bytes while transfering files from client to server, the bytes values also represent some of the control characters

StackOverflow https://stackoverflow.com/questions/18566593

Question

I'm writing a file transfer client/server application where the client is operating on windows7 and written in vb.net and the server is operating on linux mint and written in c++ (I'm using vmware) my problem is when i try to upload files to the server (such as images) the received data is missing many bytes which also represent the control characters (such as EOT, ETB,...) and I guess they're read as tcp control characters and ignored by the receiving OS. I already tested the application with simple text files (size up to 4MB) without any problem. is there a way to prevent the system from ignoring those bytes?

this is the c++ function that receives the file:

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 connected\n";
  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;
}
Was it helpful?

Solution

The issue is most likely that you sent binary data. And binary data can contain zeros. And zeroes are the normal string terminator.

This means that when you do temp.str(Rbuffer) (assuming temp is a std::stringstream) then it only gets data from Rbuffer until the first zero.

Instead of using e.g. std::stringstream use 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);
}

The important thing to remember here is that you can't use the received data as a string! If it's binary data it will with most certainty contain the string terminator and so you have to treat is as binary data and not a string (even though you can store it in a std::string).

You also need to be aware that you can't print the data, as many binary values are either unprintable or will print as "garbage".

And lastly, if you read and write binary files, you need to open them in binary modes, or you will get errors with the bytes 0x0d and 0x0a (i.e. carriage-return and newline).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top