Question

I'm writing a small Server/Client Filetransfer using Winsocket for class and it basicly works except that i can't receiv any more messages on the socket after I receiv the file and write it to my HDD.

The transmit code loosk like this:

    long size = GetFileSize(hFile, NULL);
TransmitFile(_socket, hFile, size, 0, NULL, NULL, TF_DISCONNECT);
ok = ::recv(_socket, cantwortfilename, 100, 0); // getting a confirmation (1)
cantwortfilename[ok] = '\0';
cout << cantwortfilename << endl;
char test[] = "ok!";
::send(_socket, test, strlen(test), 0); // to test if server receives again (2)

I tried it with 0 instead of size with same results.

now to the receiving on the server side:

    HANDLE hFile = CreateFile(filepathlong, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

while (1)
{
    ReadFile((HANDLE)_socket, &buffer, MAX_PATH, &dwbr, &AsyncInfo);
    GetOverlappedResult((HANDLE)_socket, &AsyncInfo, &dwbr, TRUE);
    if (dwbr == 0) break;
    WriteFile(hFile, buffer, dwbr, &dwbr, NULL);
}
char test[] = "alles ok!";
::send(_socket, test, strlen(test), 0); // sending the confirmation (1)

CloseHandle(hFile);

 i = ::recv(_socket, test, 10, 0); // receiving the test (2)
test[i] = '\0';
cout << "empfangen:" << test << endl;

The transfer of the file works fine as far as i can tell (tried rar jpg .h) and the

::send(_socket, test, strlen(test), 0); // sending the confirmation (1)

gets out fine too.

but the receiving after that gives me nothing? or something empty? I would guess something empty since the recv doesn't block the program either. But "i" will be 0 when i give it out.

to check if i made some kind of error with the stuff in the while(1) loop i tried another way to receiv the file.

the 2nd try:

    int r;
ofstream file(filepath, std::ios::out | std::ios::binary | std::ios::trunc);
char *memblock;
int size = 7766; // was the size of the file i was testing with
memblock = new char[size];
memset(memblock, 0, size);
if (file.is_open()){
    //while memory blocks are still being received
    while ((r = recv(_socket, memblock, 256, 0)) != 0)
    {
        //if there's a socket error, abort
        if (r == SOCKET_ERROR)
        {
            cout << "error" << endl;
        }
        //write client's file blocks to file on server
        file.write(memblock, r);
    }
    delete[] memblock;
    //finished sending memory blocks; file is completely transferred.
    file.close();
}

after that, again a send a recv with the same result. The file worked but receiving again got me something empty.

So can anyone tell me why and how can fix this? If possible with the least change possible?

Thanks, Martin

EDIT: Code that is working for me now:

    char csize[256];
rc = recv(_socket, csize, 256, 0);
csize[rc] = '\0';
int size = atoi(csize);
int bytes_read = 0, len = 0;

int r;
ofstream file(filepath, std::ios::out | std::ios::binary | std::ios::trunc);
char *memblock;
memblock = new char[size];
memset(memblock, 0, size);

if (file.is_open()){
    while (bytes_read < size){
        len = recv(_socket, memblock + bytes_read, size - bytes_read, 0);
        bytes_read += len;
    }
    file.write(memblock, size);
    delete[] memblock;
    file.close();
}
Was it helpful?

Solution

Your transmitter is calling TransmitFile() with the TF_DSCONNECT flag. That will close the socket after the file has finished being sent. The transmitter can't send any more data once TransmitFile() has exited (I am not sure if TransmitFile() only does a half-duplex close to close just the send direction but leaves the receive direction open, or if it does a full-duplex close on both send and receive directions - I would err on the side of caution and assume the latter).

Based on what you have shown, you need to use shutdown() and closesocket() instead of TF_DISCONNECT so you have more control over when and how the disconnect actually occurs.

Also, TransmitFile() does not send the file size, only the file data, so your receiver has no way of knowing when the file data has actually finished being received, unless it waits for a timeout (which is not a reliable solution). You need to change your transmitter to send the file size before sending the file data, then change your receiver to read the file size first and then loop until it has received the specified number of bytes.

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