Thread: Winsock messages getting eaten!

  1. #1
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879

    Unhappy Winsock messages getting eaten!

    Hey everyone, I'm having some difficulties here with winsock. This is my code, in simplified pseudo-form:
    Code:
    Client-side:
    -send a file
    -when finished sending, recv() 1 byte from server to know that
    the server is done receiving
    -immediately send another message to the server, telling it to
    send the directory listing
    
    Server-side:
    -receive a file
    -when finished receiving, send() 1 byte to client, to indicate the
    file is done receiving
    -Check for another message, and act on that.
    My problem is that this happens:
    Code:
    Client-side:
    -send a file
    -recv() 1 byte, everything's ok
    -send another message to the server
    -wait forever (literally) for the server to send the listing
    
    Server-side:
    -receive a file
    -send() 1 byte to the client
    -wait forever (literally) for the client to send another message
    Somehow, it seems that the second command the client sends (get the directory listing) gets eaten somewhere along the line, and the server never receives it. But strangely enough, when I put a Sleep(500) between getting the receive confirmation and sending the second message, the second message gets sent fine. Does anybody have any clue why or what's wrong? (the code is exactly the same in both cases except for an added Sleep)
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  2. #2
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Can you post some code?
    Yes, but it'd be super duper long and a bit hard to read.

    How does the server know how much data it has to receive?
    The client sends the filesize ahead of the file; the reason why I had the client wait for the recv() after sending is so that the server doesn't get the next message mixed in with the tail end of the last data packet. Also, I check the file that the server received and compare it to the file sent... they are always identical.

    Have you verified the exact amount was read before you send the ``OK-byte''?
    Yes, it doesn't stop receiving until the bytes received matches the filesize.

    Have you checked all send() calls for success?
    No, I guess I should check that... Thanks for pointing that out

    How did you determine that the server is waiting forever for the client message to be sent?
    Because I have it continually checking for new data to be received (i.e. another message), and after receiving the file there isn't any data.

    How do you know it doesn't hang elsewhere?
    Because the server keeps going with its life and just keeps looping through all the clients, checking if each one has data waiting. It doesn't freeze, it just doesn't receive the message when I expect it to. And, receiving the data/message is the very first step in doing anything on the server... if it doesn't receive the data, it's hard to say that it's because of something later on, since I have it pop up a messagebox the moment a message is received .

    Any ideas on the cause, or do you still want me to post my code?
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  3. #3
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Some code needed, I feel. If it's too long, attach it in a zip file or something.

    You said that putting a small delay into the process fixes the problem. It is likely then that the client isn't detecting the 1 byte confirmation from the server correctly, instead it *thinks* it's got it when in fact it hasn't, and proceeds to send the DIR. This all happens so quick, that the DIR is concatenated with the final packet of the data file, which the server receives and mis-interprets.

    Of course, I'm making this up, having not seen you code, I have no idea where the problem is, but that's my best guess for now.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  4. #4
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Okay, I guess I'll do the zip. It's the whole program, by the way.

    Well, the server side is sort of confusing, so here I'll put a bit of a summary:
    -I have a class called Client, which is where pretty much everything happens between the server and individual client.
    -I have a global vector of Client's called clients.
    -In my loop, I loop through the vector, calling doOperations() on each, removing any client that returns false when doOperations() is called (i.e. disconnected, connection reset, etc.)
    -doOperations(), based on the state of several variables, determines what to do.
    -If "msgAvailable" is true, it checks what the command
    is and does what it says, then sets msgAvailable to false.
    -Otherwise, if there is data waiting to be received, depending
    on what type of data is waiting, it receives and processes
    the data.
    -If it's receiving a file, it calls rcvFileBytes().
    -Or, if the data is a message (command), receive whatever
    data there is, and if the message is completed, set
    msgAvailable to true.
    -Otherwise, if the data is a header (the size of the
    message), receive whatever data there is.

    **PS
    Please don't hold the weak pun in the name against me
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  5. #5
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Hunter, is this still broken? I haven't had chance to look at it yet, maybe will do tonight. I just didn't want you to think we'd forgotten about ya!
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  6. #6
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    *Whew!* I was beginning to think that I was forgotten Yes, it's still broken, and I would appreciate any help towards fixing it.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  7. #7
    verbose cat
    Join Date
    Jun 2003
    Posts
    209
    I'm at work right now so I can't download the code to look (I shouldn't even be reading this! *innocent whistle*) but I had a thought at what could be the problem...

    When you are receiving that single byte of data to signal a list, how big of a buffer are you using to receive it with?
    If you are using a 1 byte buffer then my thought is wrong.
    If you are using a bigger buffer but only looking at the first byte in the buffer, then the rest of the data you think is being eaten is actually being eaten by that buffer.

    For example:
    Code:
      char single_byte_buf[1];
      recv(sock, single_byte_buf, 1, 0);
    This will only accept a single byte from the sender, whereas:
    Code:
      char recv_buf[256]; // what you might be using for the data xfer
      recv(sock, recv_buf, 256, 0); // gets the next block of data
    If the client sent a single byte immediately followed by more data, all that data would be sent at once and the recv_buf would hold it all. If you then only look at recv_buf[0] and ignore the rest, you're ignoring the data your client sent for whatever was supposed to follow that byte (i.e. eating the data! ).

    If this is the case, the reason the sleep() delay is working is because that byte is sent, then the client delays long enough for nagle to kick in. (The nagle algorithm works behind the scenes to efficiently send data, if some data is sent and then there is a delay, nagle will actually push the first set of data through and then wait for more before pushing more data over the connection). So by putting the sleep() in, you just happen to be getting lucky and nagle is saving your program. The fix would be to listen only for that one single byte and then listen for the rest (or if you use that 256 byte buffer, process the first byte and then process the rest before recv()'ing anything else).

    Hope this helps!

    PS: You don't want to leave the sleep() in there as the fix because the tcp protocol doesn't guarantee when data will arrive, only that it will in the correct order. The sleep() could fail to fix the problem if the server ends up being stuck and not doing the recv() until the client has sent both the single byte and the following data in which case it could recv() it all in one try (bringing you back to the original problem) and this would be a very difficult "bug" to track down...

    -jEssYcAt
    Last edited by jEssYcAt; 07-05-2003 at 04:02 PM.

  8. #8
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Well, the messaging system seems to be ok (you can take a look at the basic idea of how the data gets received below).

    But I now think that there's something wrong with the code for sending a file to the server. It works fine when I connect to "localhost" and send a file, but somehow when I tried sending a file to a friend over the 'net (windows 98 to windows XP), part of the file didn't get sent (the client send()'t it all, but the server didn't get all of it). The difference was something like 1 or 2 kb for a ~4mb mp3 file, nothing really significant when listening to the song, but it caused the server to never send the "ok byte", so the client would freeze until the server shut down. So I think the problem's with either the client's uploading or the server's downloading, or maybe both.

    Hope this helps you help me

    Simplified message-receiving code:
    Code:
    unsigned long msgSize;
    char buf[4];
    int rcvdBytes = 0;
    while(rcvdBytes < 4)
    {
         int bytes = recv(socket, &buf[rcvdBytes], 4 - rcvdBytes);
         if(bytes == 0 || bytes == SOCKET_ERROR)
              doSomethingAboutIt();
         else
              rcvdBytes += bytes;
    }
    msgSize = *(unsigned long*)buf;
    
    //stuff
    
    rcvdBytes = 0;
    char* msg = new char[msgSize];
    while(rcvdBytes < msgSize)
    {
         int bytes = recv(socket, &msg[rcvdBytes], msgSize - rcvdBytes);
         if(bytes == 0 || bytes == SOCKET_ERROR)
              doSomethingAboutIt();
         else
              rcvdBytes += bytes;
    }
    
    unsigned char cmd = msg[0];
    unsigned long byteIndex = 1;
    switch(cmd)
    {
         //for example:
         case OP_LOGIN:
              unsigned char nameLen;
              nameLen = (unsigned char)msg[byteIndex];
              ++byteIndex;
              char* name;
              name = new char[nameLen + 1];
              memcpy(name, &msg[byteIndex], nameLen);
              byteIndex += nameLen;
              //other stuff
              break;
    }
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  9. #9
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Get both the client and server to msgbox out the number of bytes they think they're about to send and receive.

    Send a text file containing a sequence of numbers, 1-N, where N is a big as you like. That way, it'll be easier to determine where in the process things go wrong (start, middle, end).

    The way your server program currently works is to dynamically create an array big enough to hold the complete file. If you never intend to actually use the file in memory, I'd suggest a different approach. Simple use a regular array of a fixed size, and write that the file each time put populate it. Something like this (vastly over simplified!):
    Code:
    char rcvData[4096];
    int bytes = sock.receive(rcvData, sizeof(rcvData));
    writeFile.write(rcvData, bytes);
    Don't delete the file if an error occurs, at least not until you've solved your problems.

    Looking at your server code, I don't like this:
    >>fileBytesReceived += (bytes - 1); //1st byte is status
    Why the -1 ? There isn't going to be a control byte on the front of every buffer populated by the receive() function.

    Also, with regards to the variables packetBytesReceived and fileBytesReceived, why have the two? It would be simpler to use only one counter.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

  10. #10
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    *doh* Yeah, the -1 should be a problem if not the whole packet gets received at once. But, I don't create a buffer for the entire file. I create a buffer of length packetSize (which is sent by the client in the init data), so I am actually doing what you suggested. The 1st byte of each packet is either continue or cancel, and the rest is the data. Also, the reason I have 2 counters is so that I can check:
    a) when I have a complete packet
    b) when I am finished receiving the file.

    I suppose I could do without the packet counter, but at the time it seemed easier just to use 2 counters.

    **EDIT**
    Ok, I've fixed the -1 problem, and now it only does the -1 if it's the start of a new packet (i.e. and the 1st byte is the status).
    Last edited by Hunter2; 07-05-2003 at 10:00 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  11. #11
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    *Note: I forgot to mention this, but the problem seems to only occurs on smaller files.

    Okay, I did what Hammer suggested with messageboxes telling the bytes sent/received, except I logged it to a file instead for convenience. Actually, I didn't log anything on the client side, but on the server's logfile, I noticed that the bytes received on the last packet would bring the total bytes received higher than the total filesize. Most of the time the extra data is: 0x20, 0x20, 0x20, 0x02. But when I tried a 4094-byte file it was just 1 byte extra, and on a 4095-byte file, it seemed to receive the correct amount. After this call of rcvFileBytes() though, rcvFileBytes() would get called again, this time with 2 more bytes of data received. I noted that 4 bytes and 2 bytes correspond to the size of a header and the size of the GETDIRLIST message, but the problem is, the data in these bytes is all wrong - 0x20, 0x20, 0x20, 0x02 would give a huge message size no matter what endian, and with the 2-byte receive, it varies from time to time (the last time I tried was 0xB, and 'X'). Does any of this make sense to anybody? (especially Hammer )
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  12. #12
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Hmm, you mean file-uploading, or just command-sending? Well, this is uploading:
    Code:
    //Client-side:
    -User clicks a button, which starts off the upload.
    -Message size is sent to server, which is sizeof(ICV_OP_TOSERVER)
     + sizeof(fileSize) + etc.
    
    -ICV_OP_TOSERVER command sent to server, with the packet's
    size, the filesize, filename, etc.
    -File transfer dialog pops up
    -Buffer of 4096 bytes is allocated
    -In the file-send loop ("while(!file.eof && !cancel)"), continually:
        -If the server disconnected, quit.
        -Process window messages including the "cancel" button
        -Set the 1st byte of the buffer to ICV_S_CONTINUESEND
        -Read a 4095-byte (or else however much of the file there
         is left to read) chunk of the file into the buffer at an offset
         of 1
        -Send n bytes of the buffer to the server, where n is the
         number of bytes read from the file, +1 for the status byte
        -Update the "transfer rate", progress bar, "bytes uploaded",
         etc. in the dialog
    -After the file data has all been sent, wait for a 1-byte recv() - it
    should be ICV_SR_OK, which it was the last time I bothered
    logging it to a file.
    -Send the header and command of ICV_OP_GETDIRLIST, etc.
    Last edited by Hunter2; 07-06-2003 at 03:25 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  13. #13
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    Yes, I've read the article in the FAQ True it explains some weird behaviour when I try sending a 4095-byte file, but I don't believe that is the problem here.

    The function only sends (file.gcount() + 1) bytes, so if eof was reached in the read(), only perhaps 5 bytes would be sent (status + 4 bytes read before hitting eof). Then back at the top of the while loop, the "!file.eof()" would break the loop.

    The only problem would be if the read() got the last byte but didn't read past yet, and consequently on the next iteration of the loop, a single ICV_S_CONTINUESEND message was sent (without any file data after it) without the server expecting it since the whole file was received. So I can fix that, but the main problem still remains: What on Mount Doom* is happening with screwed-up data getting received by the server??

    *Expression taken from Lord of the Rings by J.R.R. Tolkien
    Last edited by Hunter2; 07-06-2003 at 03:48 PM.
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  14. #14
    Carnivore ('-'v) Hunter2's Avatar
    Join Date
    May 2002
    Posts
    2,879
    File mode: binary
    Opened in: binary mode
    Function call: std::ifstream file(path, std::ios::in | std::ios::binary)
    File size acquired by: CreateFile(), GetFileSize(), CloseHandle()
    Other notes: File size acquired before opening with STL

    I don't think there's anything wrong there Anything else?
    Just Google It. √

    (\ /)
    ( . .)
    c(")(") This is bunny. Copy and paste bunny into your signature to help him gain world domination.

  15. #15
    End Of Line Hammer's Avatar
    Join Date
    Apr 2002
    Posts
    6,231
    Time to start debugging in a more serious way. Basically, you haven't been able to identify what the problem really is, only that it works sometimes and not others. You need to determine the circumstances more precisely.

    I'd suggest using a packet sniffer:
    http://www.softrom.net/description_u...sp?SiteID=1865
    and see what your programs are actually saying to each other. Again, use a simple text file to make it easy to follow in the trace.

    With regards to the unpredictable data you're seeing, it is possible that it's just junk from an invalid memory location, either being sent by the client, or extracted from the buffer by the server.
    By using the sniffer, you can eliminate half of the code (ie client or server) in a flash.

    Unfortunately, I'm (probably) in the same boat as vVv, in that I can't compile/run your program as I have no appropriate compiler. This makes it kinda hard to help efficiently.
    When all else fails, read the instructions.
    If you're posting code, use code tags: [code] /* insert code here */ [/code]

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Winsock issues
    By tjpanda in forum Windows Programming
    Replies: 3
    Last Post: 12-04-2008, 08:32 AM
  2. winsock help
    By Anubis208 in forum C++ Programming
    Replies: 1
    Last Post: 03-05-2008, 07:46 AM
  3. Spy++ view messages posted/sent to a control, or from it?
    By hanhao in forum Windows Programming
    Replies: 2
    Last Post: 06-24-2007, 11:07 PM
  4. Winsock Messaging Program
    By Morgul in forum Windows Programming
    Replies: 13
    Last Post: 04-25-2005, 04:00 PM
  5. Where do I initialize Winsock and catch messages for it?
    By Lithorien in forum Windows Programming
    Replies: 10
    Last Post: 12-30-2004, 12:11 PM