Thread: Client works on a LAN but don't send all the data

  1. #1
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291

    Client works on a LAN but don't send all the data

    Hello, I have been having problems with my client because isn't able to send all the data (or that's what I think). The scenario is the next:

    - 2 pc on the same LAN (both windows XP)
    - 1 server (my own server, not a professional server ) on the pc #1. That server can get a param from the header (like HTTP params) 'ECHO<crlf>' that internally means 'Return the same message you receive': if the recv header have a 'Content-Length: 0<crlf>' then sends a 'Hello from server'; else sends the content message.
    - 1 client (also my own client, less professional than the server) on pc #1. That client sends an HTTP header like

    Code:
    POST / HTTP/1.0<crlf>
    Connection: Close<crlf>
    User-Agent: DemoClient/1.0<crlf>
    Host:123.456.789.0<crlf>
    Accept: */*<crlf>
    ECHO<crlf>
    Content-Length: 4<crlf>
    <crlf>
    test<crlf>
    Ok, I run the server on pc#1 and the client on pc#1, the client send all the data, the server recv it all and resend 'test'. It works well.

    After that, from pc #2 I run the internet browser, connect to my server index page, download the client program from pc#1 (so may I think that the server doesn't have any problem, or any important problem, because I can browse through the server's index page, several links, several formats and there's no problem). Right, now I have the client on pc#2, I run it, send all the data but on the server only arrive since the '<crlf><crlf>', the message 'test' remains I-don't-know-where, the server returns nothing, and whil terminating the conexion I get some unexpected last bytes, exactly 4 bytes, and if I printf them are the message content sended by the client.
    Why does it happens when working from different pc but not when I'm work on the same? The server should work well because I can recv the data from forms of webpages settedup with method POST.
    The header request from browsers MSIE and NSN when they submit a form in method POST, haven't notably differences with the header on my client. That are a sample of the header that a MSIE browser sends to my server to submit a form in POST method:
    Code:
    POST /DIRSERVER/response.txt HTTP/1.1<crlf>
    Accept: image/gif, (more types)<crlf>
    Referer: http://123.456.789.0/<crlf>
    Accept-Language: es<crlf>
    Content-Type: application/x-www-form-urlencoded<crlf>
    Accept-Encoding: gzip, deflate<crlf>
    User-Agent: Mozilla/4.0 (compatible; MSIE 5.5...)<crlf>
    Host: 123.456.789.0<crlf>
    Content-Length: 37<crlf>
    Connection: Keep-Alive<crlf>
    Cache-Control: no-cache<crlf>
    <crlf>
    field0=text0&field1=text1&butsub=Send<crlf>
    I can't see notably differences between msie request and mine, but on the server I can get all the data (from both pc), but when I send the same request though my client the content message is left (only when the client sends the request from a different pc than the one where server is running).
    To send the data from the client I copy the header into a buffer and send it in one time. On the client I have a big buffer to recv the data also in one time (I suppose that form the moment that won't be the problem, if not my server wouldn't be able to get the profesional browsers request).

    Have someone had or have seen a problem like that?

    Thank's in advance

    Niara

    P.S. Ok, year-end so have a good new year
    Last edited by Niara; 12-31-2006 at 01:48 PM.

  2. #2
    int x = *((int *) NULL); Cactus_Hugger's Avatar
    Join Date
    Jul 2003
    Location
    Banks of the River Styx
    Posts
    902
    Your problem likely lies in your code somewhere, either in the server, the client, or both. I couldn't determine if you have code for the client, server, or both by your last post however. Post your code so we here don't have to divine the answer. (Or guess at common mistakes, like not checking recv()/send()'s return codes.)

    Also, consider a network analyzer like WireShark. It'll allow you to see what exactly gets sent over a network connection, so you can determine if your program is sending what it should. (Although I use WireShark's predecessor, Ethereal.)

    Also, when you send "test<crlf>", that's 6 bytes. You're saying the Content-Length is 4. Is this correct? (Is <crlf> part of the contents?)

    When the client runs on the same pc as the server, you may be getting a loopback interface, which might cause it to act differently then when it's on two different PCs, where it must actually send the data. (But this is not the problem.)
    long time; /* know C? */
    Unprecedented performance: Nothing ever ran this slow before.
    Any sufficiently advanced bug is indistinguishable from a feature.
    Real Programmers confuse Halloween and Christmas, because dec 25 == oct 31.
    The best way to accelerate an IBM is at 9.8 m/s/s.
    recursion (re - cur' - zhun) n. 1. (see recursion)

  3. #3
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Hello Cactus-Hugger, I didn't post any piece of code because I was thinking that's a strange net problem. Well, let me fix the problem and explanations. The scenario is the same. Also I have rewrite my server and client recv/send codes to it's simples expression (to avoid more programming errors). That's the server recv function:

    Code:
    char bff[2000];
    int nbl;
    nbl=recv(s,bff,2000,0);
    bff[nbl]='\0';
    is a simple use of recv (I know that will have problems on bigger requests, but for that test that's right because on the client's send buffer is 1024 and sends all the data at once). now the server's end connection function:

    Code:
    bool closeConection(SOCKET s)
    {
    if(shutdown(s,SD_SEND)==SOCKET_ERROR) {return false;}
    
    char bff[2000];
    bff[0]='\0';
    while(1)
        {
        int nnb=recv(s,bff,2000-1,0);
        if(nnb==SOCKET_ERROR) {return false;}
        else if(nnb!=0)
            {
            bff[nnb]='\0';
            printf("\tRebuts %d bytes inesperats durant la desconexio:\n",nnb);
            printf("%s\n\n",bff);
            }
        else {break;}
        }
    
    if(closesocket(s)==SOCKET_ERROR) {return false;}
    return true;
    }
    and now the client send function:

    Code:
    WSADATA wsa;
    SOCKET s;
    SOCKADDR_IN servidor;
    LPHOSTENT he;
    
    if(WSAStartup(MAKEWORD(2,0),&wsa)!=0) {printf("Error 0\n");getch();return false;}
    if(wsa.wVersion!=MAKEWORD(2,0)) {WSACleanup();printf("Error 1\n");getch();return false;}
    
    s=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    if(s==INVALID_SOCKET) {WSACleanup();printf("Error 2\n");getch();return false;}
    
    servidor.sin_family=AF_INET;
    servidor.sin_addr.s_addr=inet_addr("172.16.0.4");
    servidor.sin_port=htons(80);
    
    if(connect(s,(SOCKADDR*)&servidor,sizeof(servidor))==SOCKET_ERROR)
        {
        WSACleanup();
        printf("Error 3");
        getch();
        return false;
        }
    
    int bs,br;
    char sb[1024],rb[100];
    
    sprintf(sb,"POST /DIRSERV/resposta.txt HTTP/1.1\r\n");
    strcat(sb,"Accept: image/gif, image/x-bitmap, image/jpeg, image/pjpeg, application/x-shockwave-flash, */*\r\n");
    strcat(sb,"Referer: http://172.16.0.4\r\n");
    strcat(sb,"Accept-Language: es\r\n");
    strcat(sb,"Content-Type: application/x-www-form-urlencoded\r\n");
    strcat(sb,"Accept-Encoding: gzip, deflate\r\n");
    strcat(sb,"User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; .NET CLR 1.1.4322)\r\n");
    strcat(sb,"Host: 172.16.0.4\r\n");
    strcat(sb,"Content-Length: 36\r\n");
    strcat(sb,"Connection: Keep-Alive\r\n");
    strcat(sb,"Cache-Control: no-cache\r\n\r\n");
    
    printf("Envia HDR: ");
    bs=send(s,sb,strlen(sb),0);
    printf("%d bytes ok\n",bs);
    
    printf("Envia PRM: ");
    sprintf(sb,"txt0=Texte+0&txt1=Texte+1&sbm=Enviar\r\n");
    bs=send(s,sb,strlen(sb),0);
    printf("%d bytes ok\n",bs);
    
    br=0;
    printf("\nRebent resposta servidor...\n");
    while(br!=SOCKET_ERROR)
        {
        br=recv(s,rb,100,0);
        if(br==0 || br==WSAECONNRESET)
            {
            printf("\n\nConexio finalitzada.\n");
            break;
            }
        if(br<0) {break;}
        rb[br]='\0';
        printf("%s",rb);
        }
    shutdown(s,SD_BOTH);
    closesocket(s);
    WSACleanup();
    also the simple expresion for the send algorithm. the header for that request is the same I get from a request in MSIE to my server from the next html form:

    Code:
    <html><head></head><body>
    <form action="http://172.16.0.4/DIRSERV/resposta.txt" method="POST">
    <input type="text" name="txt0" value="Texte 0"><br>
    <input type="text" name="txt1" value="Texte 1"><br><br>
    <input type="submit" name="sbm" value="Enviar">
    </form></body></html>
    That's what I have been doing. First start my server on PC#1 (172.16.0.4), run MSIE on PC#2 (172.16.0.3), connect and load the form page (that page is in PC#1, the server reads the 'GET' statement from MSIE to get that page, and still no errors), click submit and my server can get all the data sended from MSIE running on PC#2. I'll attach an image at the end (image00).

    Right, now I have the MSIE headers that work, so I create my client (as it appears at the sample code I've posted), run server on PC#1, client on PC#1 (the client sends the data directly, without web form), and on the server I get all the data. There's no errors here.

    And in the next step is where I can't get the data. I run the server on PC#1, the client on PC#2 (the same headers as before, the same client program), and on server I don't get the final params, the data is break after the <crlf><crlf>. And still something alse: the server is able to read the file requested in the 'POST' statement and return it to the client, and in all the cases works well. After send the file (a simple text file of 18 bytes), the client is able to get it without problems, the server calls the 'closeConnection()' function and in that case I get the alert of 'Unexpected extra bytes received'. I'll attach an image of that at the end (image001).

    Why the same header and the same client programs run diferently when the client isn't in the same pc that the server? And why MSIE don't give me that problem? Knowing that my server can understand MSIE (also I have tested it with NSN and also works well) I should think that the problem is with the client... but then if the problem is in the client, why a system PC#1SERVER/PC#1CLIENT works, and fails the system PC#1SERVER/PC#2CLIENT?

    As you can see on the attached images, the first image is for the PC#1SERVER/PC#1CLIENT, and is exactly the same result for PC#1SERVER/PC#2MSIE. And the second image is the PC#1SERVER/PC#2CLIENT, the data is broken after the <crlf><crlf> (I have translated 'cr'->'<br>' and 'lf'->'<bn>'), so I can see

    Code:
    ...Keep-Alive<br><bn><br><bn>
    and after that nothing else, while in the first image you can see that I can get all the data. It seems strange to me, I haven't any idea of what's happening.

    More explications: I have been testing it with the router's port 80 opened and closed, but the error is always the same.

    I'll take a look at WireShark to see what I'm really doing.

    Thank's

    Niara
    Last edited by Niara; 01-02-2007 at 01:41 PM.

  4. #4
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    I forgot something else, you comented

    Code:
    Also, when you send "test<crlf>", that's 6 bytes. You're saying the Content-Length is 4.
    Is this correct? (Is <crlf> part of the contents?)
    Mmmm, on the first post I was trying several codes, and finally I get a mixed it all (also the hurry to post the code and go to the end-year dinner, some nervous for the night party... ). But yes, when I get the 'Unexpected extra bytes' thye n&#186; of extra bytes also includes de final <crlf>, but the MSIE header, while sending the 'Content-Length: 36<crlf>' do not include the final <crlf>, because the form parameters are 36 bytes; that's the header that MSIE creates for that request, but if I do the request with NSN the content length is also 36 but at the end of the parameters there's any <crlf> attached, but that's doesn't give any error because from the server I can get all the data even if is sended from PC#1, PC#2, MSIE or NSN). Also, on my client when I send the params, the n&#186; on bytes send is 38 in all the cases, so the client sends the data but does'n arrive at the server; also strange because MSIE and NSN can send the data and it arrives to the server without errors. Each time I think about that I find it more strange

    Niara

  5. #5
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    I have been testing some other tricks: I can see that when I'm working with the server and the client on the same PC, all the 'send()' from the client are sended like a single one, so if I try to use two 'recv()' on the client the second one never finishes; and when the client isn't on the server's pc, I should use several 'recv()' on the server to get all the data; but the strange thing happens with the professional browsers: I can get browser request in a single 'recv()' function. I will try to send the client request in a single 'send()'... but that can't be the problem, because in all the manuals on client/server I should check the n&#186; of bytes sended (or received by the client) and if not enought I have to re-send() the not sended bytes. What a fuss...

    Niara

  6. #6
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    Message fragmentation and reassembly is your problem to fix, when using a TCP connection.

    Both send() and recv() can return having sent (or received) the total amount of data to be sent.

    All the TCP protocols use some kind of mark (say a length or a character sequence) to mark the end of the transmission. Until that is reached, you have to be prepared to deal with the message in fragments.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  7. #7
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Thank's Salem, I'll take a look to that.

    Niara

  8. #8
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    I think that I have find the solution... well, I think I've found something, but I haven't implemented yet. That's what I have (for the moment I have tested only on paper ):

    1-. Use a recv buffer of 4 bytes
    2-. Start the recv loop
    2.1. Check that the n&#186; of bytes recv is greater than 0
    3-. Because the point 2.1 does not solve anything, compare the size of the recv buffer with the n&#186; of bytes recv:
    3.1. if buffer-length > recv-length -> transmission finished
    3.2. if buffer-length == recv-length (never will be buff-len < recv-len)
    3.2.1 if buffer recv is '\r\n\r\n' -> header transmission finished; now check the 'Content-Length:' of the header; if exists and is >0 continue a recv loop to get the message part. Else the transmission is finished.

    I have think on do that using a buffer[1], but would be slow; also will be slow a buffer[4], but is the only way to check 'on the fly' the double <crlf> (I think). Let me implement and see what happens...

    Salem: I have been searching on message fragmentation, but I have find that is used for multimedia purposes (parts of songs, voice, ...). I have problems using a simple html form submit, and the headers send doesn't specify a multibloc transmission. Well, I haven't the problem when MSIE or NSN submits it (my server can get all the data), the problem should be with my client. However I'll will have in mind that for future (hope) implementations.

    Niara

  9. #9
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    TCP is a stream - just a variable length array of bytes.

    HTML specifies a content length in the response, so you need to
    a) keep reading the stream until you see a content-length appear
    b) then read that much more data
    c) close the connection.

    > Use a recv buffer of 4 bytes
    If you want, but that in itself doesn't solve the problem.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  10. #10
    Registered User
    Join Date
    Mar 2005
    Location
    Juneda
    Posts
    291
    Hey Salem, yes I know that. The problem was (now I can see that's a stupid problem) that my server was expecting to get all the data with only one recv call (because the buffer size should be sufficient). The problem was that if a client sends the data using 2 send() calls and the server try to get all the data in one single recv() call, on closing the connection and calling several times recv() to 'fflush' the data (suppose that's a good aproximation on what the endig loop does), it receives the data send in the second senc() call from the client (don't read that as is, I'm not usual english speaker-reader-writer it's hard to explain). So if the client calls 2 times to send(), the server should call also 2 times to recv(), no?

    Now I'm using a 1024 bytes buffer and the trick that finally I've used is to check for <crlf><crlf> because (in HTTP headers) will be always (or since now - I think-) at the end of the header; so I check for that end, if I don't find it I continue with another recv (appendig the data received to the buffer of data received, and so on; but if the <crlf><crlf> is in the buffer of data received I check the next

    Code:
    char *pch;
    pch=strstr(bff,"\r\n\r\n");
    if(!pch) {return;}//Still no appears the end of the header
    else
        {
        if(strlen(pch)==4)
            {
            //reached the end of the header
            //on return, the main recv loop will check the content-length value, if it
            //says that there's also a message then call recv() another time
            }
        else
            {
            //reached the <crlf><crlf> in the middle of the data of the buffer
            //so check for the content-length statement
            if(contentlength<=strlen(pch))
                {
                //I have read all the data, include the message
                }
            }
        r=true;
        }
    Previously to call that function, I call another function that interprets the HTTP statements, so I can get the 'Content-length' value. For the moment it works well, from both pc, from professional clients, from my poor client, now is time to optimize the code. I have also thought on send a last send(socket,NULL,0,0) from the client, so using a simple server loop checking for the bytes received will tell me the end of the transmision, but I'm not sure that all the clients do that.

    I'm also thought about use something to prevent the infinite loop in headers with errors, and also a function that could parse HTTP statements from blocs of data. A lot of work to do, but now I can start it.

    Thank's.

    Niara

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. How to Send Mac Address From Client to Server
    By Lieyza197 in forum C Programming
    Replies: 2
    Last Post: 05-27-2009, 09:58 AM
  2. Bitmasking Problem
    By mike_g in forum C++ Programming
    Replies: 13
    Last Post: 11-08-2007, 12:24 AM
  3. Replies: 4
    Last Post: 06-14-2005, 05:45 AM
  4. can't insert data into my B-Tree class structure
    By daluu in forum C++ Programming
    Replies: 0
    Last Post: 12-05-2002, 06:03 PM
  5. Client-Server Data Read Problem
    By bob2509 in forum C Programming
    Replies: 8
    Last Post: 11-06-2002, 11:47 AM