上述这三个技术都适用于输入和输出操作(read、write,及其变体recv/send, readv/writev, recvfrom, sendto)。不过我们也期待可以用于connect的技术,因为TCP内置的connect超时相当长(典型值为75秒),而我们在写服务器程序的时候,也不会希望一个连接的建立需要花费这么长时间。select可用来在connect上设置超时的先决条件是相应的套接字是非阻塞的,而那两个套接字选项对connect并不适用;同时也应当指出,前两个技术适用于任何描述符,而第三个技术仅仅适用于套接字描述符。
>>>>使用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); } }