0

I am writing a non-blocking chat server, so far the server works fine, but I can't figure out how to correct for partial sends if they happen. The send(int, char*, int); function always returns 0 on a success and -1 on a failed send. Every doc/man page I have read says it should return the number of bytes actually feed to the network buffer. I have checked to be sure that I can send to the server and recv back the data repeatedly without problem.

This is the function I use to call the send. I both tried to print the return data to the console first, then tried line breaking on the return ReturnValue; while debugging. Same result, ReturnValue is always 0 or -1;

int Connection::Transmit(string MessageToSend)
{         
    // check for send attempts on a closed socket
    // return if it happens.
    if(this->Socket_Filedescriptor == -1)
        return -1;

    // Send a message to the client on the other end
    // note, the last parameter is a flag bit which 
    // is used for declaring out of bound data transmissions.
    ReturnValue  = send(Socket_Filedescriptor,
                         MessageToSend.c_str(),
                         MessageToSend.length(),
                         0); 

    return ReturnValue;        
}
joostdevries
  • 930
  • 1
  • 6
  • 13
  • 1
    When the return value is -1, what error are you getting? Check the value of `errno` or use `perror` – Charles Salvia Jan 01 '13 at 20:01
  • 1
    When `send` returns `-1` you should check `errno` on POSIX systems (e.g. Linux or OSX), or use `WSAGetLastError` on Windows. This will help you understand what went wrong. – Some programmer dude Jan 01 '13 at 20:02
  • `send(int, char*, int);` is not exactly the Berkeley Socket `send`. Which platform are you using? Have you tried to use `write` instead of `send`? – n. m. could be an AI Jan 01 '13 at 20:13
  • I forgot an int when I said that, The code I listed is correct however. – user1908813 Jan 01 '13 at 20:20
  • Have you checked for other send() functions that might be in scope? Try the call with ::send() instead of send() to force global resolution. – arayq2 Jan 01 '13 at 21:04
  • 1
    send() returns zero if you supply a length argument of zero. Have you checked that? The length you supply should be the length of the c_str(). – user207421 Jan 01 '13 at 22:04
  • The problem went away so to speak. I tried to send a massive string out to simulate a partial send. My system went to a crawl and I had to reboot. After I rebooted the code now returns bytes properly. I'm going to guess its a system level problem rather than in my code. I'm running Ubuntu 12.04.1 – user1908813 Jan 01 '13 at 22:11
  • @user1908813 The questions remain: (a) does your length() method return zero, and (b) does it return the actual length of the c_str()? It is several orders of magnitude, by which I mean at least six, more likely that the error is in your code rather than the operating system. – user207421 Jan 02 '13 at 08:54
  • @EJP To answer that I did this.. printf("%i of %i",strlen(MessageToSend.c_str()), MessageToSend.length()); On a return value of 0 from send. Output was 13 of 13. The results still vary but are mostly 0. I just ignore 0 results and it seems to work fine. – user1908813 Jan 04 '13 at 23:01

1 Answers1

0

Why don't you try to send in a loop? For instance:

int Connection::Transmit(string MessageToSend)
{         
    // check for send attempts on a closed socket
    // return if it happens.
    if(this->Socket_Filedescriptor == -1)
        return -1;

    int expected = MessageToSend.length();
    int sent     = 0;

    // Send a message to the client on the other end
    // note, the last parameter is a flag bit which 
    // is used for declaring out of bound data transmissions.
    while(sent < expected) {
      ReturnValue  = send(Socket_Filedescriptor,
                         MessageToSend.c_str() + sent, // Send from correct location
                         MessageToSend.length() - sent, // Update how much remains
                         0); 
      if(ReturnValue == -1)
        return -1; // Error occurred
      sent += ReturnValue;
    }

    return sent;        
}

This way your code will continually try to send all the data until either an error occurs, or all data is sent successfully.

RageD
  • 6,693
  • 4
  • 30
  • 37
  • I tried something similar to this at first. My server went into an infinite loop, and my client was spammed to death with repeats of the same message. Since the return was always 0, despite it sending all the data each time it tried. – user1908813 Jan 04 '13 at 23:06
  • Sorry - I modified my original post. I added a simple condition to check for 0. Remember that if the `send` call returns 0, then the socket has been closed. – RageD Jan 05 '13 at 03:30
  • Actually if that was the result I was getting, then it wouldn't be a problem. In my case the socket remains open, and functional for future reads and writes dispite the result of 0 – user1908813 Jan 06 '13 at 02:13
  • My fault - I re-modified my original post. I read my code wrong. `read` returns 0 when the connection terminated (so strike my comment above, please - it is wrong). `send` can return 0 indefinitely. Maybe this post will help: http://stackoverflow.com/questions/3081952/with-c-tcp-sockets-can-send-return-zero – RageD Jan 06 '13 at 02:29