LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Networking (https://www.linuxquestions.org/questions/linux-networking-3/)
-   -   Sockets - Prevent Partial Writes (https://www.linuxquestions.org/questions/linux-networking-3/sockets-prevent-partial-writes-4175457798/)

Brandon9000 04-11-2013 09:50 AM

Sockets - Prevent Partial Writes
 
I have written a socket client program in C++. At some point, I have to send data, and this is how I do it:

lenSent = write(serverSocket,sendBuf, len);

I can use send() instead of write(). It makes no difference to this question. I have set it to be non-blocking, because the thread must not get stuck. Unfortunately, it is connecting to a server which exits if I do a partial write to the socket.

How can I prevent a non-blocking socket from doing a partial write? Is there some way to poll it and make sure that it can handle the number of bytes I wish to send?

Thanks.

Brandon

manu-tm 04-11-2013 11:20 AM

For that, you can use 'select'. You will find useful info in manpages:
Code:

man send
Also:
http://beej.us/guide/bgnet/output/ht...age/index.html
http://beej.us/guide/bgnet/output/ht...ed.html#select

Brandon9000 04-11-2013 11:57 AM

The man page for send says:

"The select(2) call may be used to determine when it is possible to send more data."

This isn't really enough for me to know how to do it. I have never used select before.

manu-tm 04-11-2013 01:57 PM

Have you read this: http://beej.us/guide/bgnet/output/ht...d.html#sendall ?

Here is an example:

Code:

/*
 * send_full() - Socket must be opened in non-blocking mode
 */

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <sys/select.h>

#define SEND_RECV_TIMEOUT_SEC        1
#define SEND_RECV_TIMEOUT_USEC        0

enum {
        SELECT_ERROR,
        SELECT_TIMED_OUT,
        SELECT_TRUE,
        SELECT_FALSE
};

int writable_data_is_available_on_socket(int sck)
{
        fd_set                write_set;
        struct timeval        timeout;
        int                i;

        FD_ZERO(&write_set);
        FD_SET(sck, &write_set);
        timeout.tv_sec = SEND_RECV_TIMEOUT_SEC;
        timeout.tv_usec = SEND_RECV_TIMEOUT_USEC;
        if ((i = select(sck + 1, NULL, &write_set, NULL, &timeout)) == -1) {
                fprintf(stderr, "select() error: %s\n", strerror(errno));
                fflush(stderr);
                return SELECT_ERROR;
        } else if (i == 0) {
                return SELECT_TIMED_OUT;
        } else {
                if (FD_ISSET(sck, &write_set))
                        return SELECT_TRUE;
                else
                        return SELECT_FALSE;
        }
}

/*
 * Return n bytes sent or -1 if error (connection closed by server or ?)
 */
int send_full(int sck, const char *str)
{
        int        len = strlen(str), i, j = 0;

        while (writable_data_is_available_on_socket(sck) == SELECT_TRUE) {
                if ((i = send(sck, str + j, len, 0)) != -1) {
                        if (i > 0) {
                                j += i;
                                len -= i;
                                if (len == 0)
                                        break;
                        }
                } else {
                        j = -1;
                        if (errno == EPIPE) {
                                fprintf(stderr, "Connection closed by server\n");
                                fflush(stderr);
                        } else {
                                fprintf(stderr, "send() error: %s\n", strerror(errno));
                                fflush(stderr);
                        }
                        break;
                }
        }
        return j;
}


Brandon9000 04-11-2013 02:01 PM

Thanks! Does select do the write itself?

manu-tm 04-11-2013 02:17 PM

Quote:

Originally Posted by Brandon9000 (Post 4929907)
Thanks! Does select do the write itself?

No, you should use send_full() instead of write() inside your code.

Brandon9000 04-11-2013 02:36 PM

Thanks again. I am also experimenting with checking to see how many unsent bytes are in the socket's internal buffer and waiting until it reaches zero with:

int error, value;
for (.....value > 0.....)
error = ioctl(serverSocket, SIOCOUTQ, &value);

Brandon


All times are GMT -5. The time now is 06:21 AM.