Search code examples
c++socketsboost-asioifstreamofstream

Writing simple file-transfer program using boost::asio. Have major send\receive desync


I am learning boost::asio network programming and tried to make simple file transfer exercise, using blocking sockets, and so, stuck upon strange issue issue.

Server (receiver) loop is following:

while (true){
    int bufSize{ static_cast<int>(pow(2, 18)) };
    char* buf{ new char[bufSize] };

    __int64 currPos{ 0 };
    __int64 fileSize;
    std::string fileName;
    mSocket->receive(buffer(buf, bufSize)); // here we get pre-defined packet with XML
    ParseDescXML(std::string{ buf }, &fileName, &fileSize); // and parse this XML, get name and size

    std::ofstream ofs(mSavePath + fileName, std::ios::binary);
    if (ofs.is_open()){
        while (currPos != fileSize) {
            if (bufSize > fileSize - currPos){
                delete[] buf;
                bufSize = fileSize - currPos;
                buf = new char[bufSize];
            }
            mSocket->receive(buffer(buf, bufSize));
            ofs.write(buf, bufSize);
            currPos += bufSize;
            std::cout << "SERVER " << currPos << std::endl;
        }
    }

    delete[] buf;
    ofs.close();
    slDebug("Receive completed"); // output some stuff, not related to issue
}

client (sender) loop is following:

mWorkerOccupied = true;
std::ifstream ifs(filePath, std::ios::binary);

if (!ifs.is_open()){
    mWorkerOccupied = false;
    return false;
}

mFileName = filePath.substr(filePath.find_last_of('\\') + 1, filePath.length());
mCurrPos = 0;
mFileSize = GetFileSize(&ifs);

std::string xmlDesc{ MakeXMLFileDesc(mFileName, mFileSize) }; // here we make XML description
xmlDesc.push_back('\0');

int bufSize{ static_cast<int>(pow(2, 18)) };
char* buf{ new char[bufSize] };

mSocket->send(buffer(xmlDesc.c_str(), bufSize)); // and send it.

while (mCurrPos != mFileSize){
    if (bufSize > mFileSize - mCurrPos){
        delete[] buf;
        bufSize = mFileSize - mCurrPos;
        buf = new char[bufSize];
    }
    ifs.read(buf, bufSize);
    mSocket->send(buffer(buf, bufSize));
    mCurrPos += bufSize;

    std::cout << "CLIENT " << mCurrPos << std::endl;
}

ifs.close();
delete[] buf;
mWorkerOccupied = false;

slDebug("SendFile completed");

All this stuff is running in parallels threads. From my understanding it should be working this way:

  1. Server thread runs servers and hangs, until incoming connection (working as expected, so I did not include this code here).
  2. Client thread runs after some time and connects to server (working as expected)
  3. Server waiting for first packet, contains XML (working as expected)
  4. Client sends XML, server gets it (working as expected)
  5. Client starts to send actual binary data, server get it. Here we have major problem.

I have a output of current position of file in both client and server loop. I expect it to be something like:

CLIENT 228 // first we send some data
SERVER 228 // Server gets it and outputs the same file pos

or

CLIENT 228
CLIENT 456
SERVER 228
SERVER 456

But what I am actually getting - confuses me...

SERVER 499384320
SERVER 499646464
CLIENT 88604672
SERVER 499908608
CLIENT 88866816
SERVER 500170752
SERVER 500432896
SERVER 500695040
SERVER 500957184

Far more messages regarding receiving something by server, than client ones about sending. How it can be? Literally, looks like client sent only 80mb of data, while server already received 500mb of data... I thought, that server thread should wait on receive(), since I am using blocking socket, but this is strange. Could someone explain me, why I have this huge desync?


Solution

  • You're assuming that receive reads the entire buffer size at once, but it doesn't necessarily:

    The receive operation may not receive all of the requested number of bytes. Consider using
    the read function if you need to ensure that the requested amount of data is read before the
    blocking operation completes
    

    receive returns the amount of data read, you should change your code to something like:

    size_t recvd = mSocket->receive(buffer(buf, bufSize));
    ofs.write(buf, recvd);
    currPos += recvd;