Chapter 14 - Advanced IO functions

1. Socket timeout

  Sockets function to set the IO timeout in three ways:

(1) call alarm.

(2)select

(3) use SO_RECTIMEO and SO_SNDTIMEO options

  The above three methods is suitable for input and output operations (read, write, sendto, recvfrom ..)

  (1) (2) applies to all file descriptors, (3) applies to socket

  connect long built-in timeout (typically 75 seconds), select the premise may be used to connect the corresponding socket in non-blocking mode. (3) suitable for connect.

2. Some examples set timeout

2.1 alarm

  Involving signal to avoid multi-threading, the signal itself is moderate global resource, so pay attention to the impact on other signals used

int
connect_timeo(int sockfd, const SA *saptr, socklen_t salen, int nsec)
{
        Sigfunc *sigfunc;
        int             n;

        sigfunc = Signal(SIGALRM, connect_alarm);
        if (alarm(nsec) != 0)
                err_msg("connect_timeo: alarm was already set");

        if ( (n = connect(sockfd, saptr, salen)) < 0) {
                close(sockfd);
                if (errno == EINTR)
                        errno = ETIMEDOUT;
        }
        alarm(0);                                       /* turn off the alarm */
        Signal(SIGALRM, sigfunc);       /* restore previous signal handler */

        return(n);
}

static void
connect_alarm(int signo)
{
        return;         /* just interrupt the connect() */
}
void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
        int     n;
        char    sendline[MAXLINE], recvline[MAXLINE + 1];

        Signal(SIGALRM, sig_alrm);

        while (Fgets(sendline, MAXLINE, fp) != NULL) {

                Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

                alarm(5);
                if ( (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) {
                        if (errno == EINTR)
                                fprintf(stderr, "socket timeout\n");
                        else
                                err_sys("recvfrom error");
                } else {
                        alarm(0);
                        recvline[n] = 0;        /* null terminate */
                        Fputs(recvline, stdout);
                }
        }
}

static void
sig_alrm(int signo)
{
        return;                 /* just interrupt the recvfrom() */
}

2.2 Use select

int
readable_timeo(int fd, int sec)
{
        fd_set                  rset;
        struct timeval  tv;

        FD_ZERO(&rset);
        FD_SET(fd, &rset);

        tv.tv_sec = sec;
        tv.tv_usec = 0;

        return(select(fd+1, &rset, NULL, NULL, &tv));
                /* 4> 0 if descriptor is readable */
}
/* end readable_timeo */

2.3 SO_RCVTIMEO 

void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
        int                             n;
        char                    sendline[MAXLINE], recvline[MAXLINE + 1];
        struct timeval  tv;

        tv.tv_sec = 5;
        tv.tv_usec = 0;
        Setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));

        while (Fgets(sendline, MAXLINE, fp) != NULL) {

                Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);

                n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
                if (n < 0) {
                        if (errno == EWOULDBLOCK) {
                                fprintf(stderr, "socket timeout\n");
                                continue;
                        } else
                                err_sys("recvfrom error");
                }

                recvline[n] = 0;        /* null terminate */
                Fputs(recvline, stdout);
        }
}

 

3. recv and send functions

       ssize_t recv(int sockfd, void *buf, size_t len, int flags);
       ssize_t send(int sockfd, const void *buf, size_t len, int flags);

  In particular flags parameters:

  MSG_DONTROUTE:

    And SO_DONTROUTE socket option similar, SO_DONTROUTE is to modify the socket to reach the long-term effective, MSG_DONTROUTE is a single valid.

    According to the normal mechanisms of IPv4, IP packets need to find appropriate local interface based on destination address and routing table, if you can not determine the local interface, it will error.

    You can use this option to bypass the above mechanisms, mandatory issued from the interface. Routing daemon did.

  MSG_DONTWAIT

    Open the temporary non-blocking flag, carried IO, shut down non-blocking flag

  MSG_OOB

    Let this call for receiving or sending of-band data.

    On a TCP connection with a byte as a data transmission band. Band data is expedited data.

  MSG_PEEK

    Allows viewing-readable data, and the recv or recvfrom returns, the data remains in the buffer, not discarded.

  MSG_WAITALL

    Inform the kernel does not return before all the specified amount of data has not been read. This can simplify readn

#define readn(fd, ptr, n)    recv(fd, ptr, n, MSG_WAITALL)

    Even so, it is also possible to read data less: (a) an interrupt signal, (b) connection termination (c) a socket error

 

Guess you like

Origin www.cnblogs.com/yangxinrui/p/12466926.html