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