3:使用較新的SO_RCVTIMEO和SO_SNDTIMEO套接字選項。這種方法的問題在於並非所有的實現都支持這兩個套接字選項。
linux
上述這三個技術都適用於輸入和輸出操做(read、write。及其變體recv/send, readv/writev, recvfrom, sendto)。socket
只是咱們也期待可以用於connect的技術,因爲TCP內置的connect超時至關長(典型值爲75秒),而咱們在寫server程序的時候,也不會但願一個鏈接的創建需要花費這麼長時間。函數
select可用來在connect上設置超時的先決條件是對應的套接字是非堵塞的。而那兩個套接字選項對connect並不適用。同一時候也應當指出,前兩個技術適用於不論什麼描寫敘述符。而第三個技術只適用於套接字描寫敘述符。post
>>>>使用select對connect設置超時:性能
#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <netdb.h> #include <sys/types.h> #include <netinet/in.h> #include <sys/socket.h> #include <unistd.h> #include <fcntl.h> #include <sys/select.h> #include <time.h> #define PORT 9900 #define MAXDATASIZE 5000 int main(int argc, char **argv) { int sockfd, nbytes; char buf[1024]; struct hostent *he; struct sockaddr_in servaddr; if(argc != 2) { perror("Usage:client hostname\n"); return 0; } if((he = gethostbyname(argv[1])) == NULL) { perror("gethostbyname"); return 0; } if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) { perror("create socket error"); return 0; } bzero(&servaddr, sizeof(servaddr)); servaddr.sin_family = AF_INET; servaddr.sin_port = htons(PORT); servaddr.sin_addr = *((struct in_addr *)he->h_addr); fcntl(sockfd, F_SETFL, O_NONBLOCK); timeval timeout = {3, 0}; if(connect(sockfd, (SA*)&servaddr, sizeof(struct sockaddr)) == -1) { if(errno != EINPROGRESS) { close(sockfd); perror("connect error"); return 0; } } fd_set readSet; FD_ZERO(&readSet); FD_ZERO(&writeSet); FD_SET(sockfd, &writeSet); int ret = select(sockfd+1, &readSet, &writeSet, NULL, &timeout); printf("%d", ret); }
#include <unp.h> static void connect_alarm(int); 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 = ETIMEOUT; } 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() */ }
#include <unp.h> static void sig_alarm(int); void dig_cli(FILE* fp, int sockfd, const SA* pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE], recvline[MAXLINE+1]; Signal(SIGALRM, sig_alarm); while(Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, preservaddr, serlen); alarm(5); /* set TIMEOUT 5 seconds */ if((n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL)) < 0) { if(errno == EINTR) fprintf(stderr, "socket timeout\n"); else err_sys("recvfrome error"); }else { alarm(0); /* if success then turn off the alarm */ recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); } } } static void sig_alarm(int signo) { return ; /* just interrupt the recvfrom() */ }
#include <unp.h> int readable_timeo(int fd, int sec) { fd_set rset; struct timeval tv; FD_ZERO(&rset); /* reset the file discriptor set */ FD_SET(fd, &rset); tv.tv_sec = sec; /* set struct timeval */ tv.tv_usec = 0; return (select(fd+1, &rset, NULL, NULL, &tv)); }
#include <unp.h> void dig_cli(FILE* fp, int sockfd, const SA* pservaddr, socklen_t servlen) { int n; char sendline[MAXLINE], recvline[MAXLINE+1]; while(Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, preservaddr, serlen); if(readable_timeo(sockfd, 5) == 0) { fprintf(stderr, "socket timeout\n"); } else { n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL); recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout); } } }
#include <unp.h> void dig_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, &tv, sizeof(tv)); while(Fgets(sendline, MAXLINE, fp) != NULL) { Sendto(sockfd, sendline, strlen(sendline), 0, preservaddr, serlen); 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); } }