1
votes

I am using tcp socket server and client in c. Using AF_INET, SOCK_STREAM and IPPROTO_TCP

My send function in client side

sent_now = send(sockId, buffer + sent_total, len - sent_total, MSG_DONTWAIT);

When I send MSG up to size like 20K-40KB, It works fine. When I send MSG up to size like 365K (Thats what I need), I receive the following error in the server Side: Resource temporarily unavailable!

My receive function in server side

totalRecvMsgSize = recieve ( clntSocket, Buffer, RCVBUFSIZE , MSG_DONTWAIT);

I send int data type.

How can I receive all the array in one send and receive operation?

old post

There is a post What can cause a “Resource temporarily unavailable” on sock send() command, where Davide Berra says that

That's because you're using a non-blocking socket and the output buffer is full.

From the send() man page

When the message does not fit into the send buffer of the socket, send() normally blocks, unless the socket has been placed in non-block- ing I/O mode. In non-blocking mode it would return EAGAIN in this case.

EAGAIN is the error code tied to "Resource temporarily unavailable"

Consider using select() to get a better control of this behaviours

My question is:

*1) How can I receive all the array in one send and receive operation? *

2) does select() help me in this array size?

3) Can I change the buffer sizes and how?

2

2 Answers

1
votes

Since this is a stream socket, you use a loop on send(), and MSG_WAITALL on recv().

Consider these helper functions:

/* Receive the entire buffer.
 * Returns 0 if success, nonzero errno otherwise.
*/
static int recv_all(const int sockfd, void *buffer, const size_t len)
{
    ssize_t n;

    n = recv(sockfd, buffer, len, MSG_WAITALL);
    if (n == 0)
        return errno = EPIPE; /* Other end will not send more data */
    else
    if (n == -1)
        return errno;
    else
    if (n < -1)
        return errno = EIO;   /* Should never occur */
    else
    if (n != (ssize_t)len)
        return errno = EINTR; /* Interrupted, or sender goofed */
    else
        return 0;
}

/* Send the entire buffer.
 * Returns 0 if success, nonzero errno otherwise.
*/
static int send_all(const int sockfd, const void *buffer, const size_t len)
{
    const char       *pos = (const char *)buffer;
    const char *const end = (const char *)buffer + len;
    ssize_t           n;

    while (pos < end) {

        n = send(sockfd, pos, (size_t)(end - pos), 0);
        if (n > 0)
            pos += n; 
        else
        if (n != -1)
            return errno = EIO;
        else
            return errno;
    }
}
0
votes
  1. You can't reliably achieve this. You can always code up your own sendall and recvall functions that set the socket to blocking, then repeatedly call send (/recv) until all the data is sent/received. (Usually a single send call with a blocking socket will result in all data being sent in one operation but there are situations [signal after some data transferred, for example] that will cause an early return, so you should not depend on that.)

  2. You can use select to achieve the same thing with non-blocking sockets but it makes buffer management more complex. You need to keep track of where you are in each buffer / how much data remains, and when select reports that a socket is "readable" or "writable" make a new attempt to send/receive at the appropriate place in the respective buffer.

  3. Yes, you can make the buffer sizes whatever you like, but if you mean "can I set the system buffer sizes somehow to avoid this?" then no, there is no way to configure the system to make this work 100% reliably without additional code. TCP does not maintain message boundaries. Your protocol must impose boundaries atop the logical stream TCP provides.