超时检测的必要性:避免进程在没有数据时无限制地阻塞,当设定的时间到时,进程从原操作返回继续运行。
方法(1):使用setsockopt函数
时间结构体 struct timeval tv;
可设定
tv.tv_sec = 5; // 设置5秒时间
tv.tv_usec = 0;
然后设置超时选项
setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
注意:将进程中和sockfd相关的阻塞,变为非阻塞。
实例代码:
server.c
1 #include<stdio.h> 2 #include<stdlib.h> 3 #include<sys/types.h> 4 #include<sys/socket.h> 5 #include<unistd.h> 6 #include<netinet/in.h> 7 #include<arpa/inet.h> 8 #include<string.h> 9 #include<errno.h> 10 11 #define N 64 12 #define err_log(log) do{ perror(log); exit(1);}while(0) 13 14 int main(int argc, const char *argv[]) 15 { 16 int sockfd, connectfd; 17 char buf[N]; 18 struct sockaddr_in serveraddr, clientaddr; 19 socklen_t len = sizeof(clientaddr); 20 struct timeval tv; 21 socklen_t optlen = sizeof(tv); 22 23 if(argc != 3) 24 { 25 fprintf(stderr, "Usage:%s serverip port", argv[0]); 26 return -1; 27 } 28 29 sockfd = socket(AF_INET, SOCK_STREAM, 0); 30 if(sockfd < 0) 31 err_log("fail to sockfd"); 32 33 serveraddr.sin_family = AF_INET; 34 serveraddr.sin_addr.s_addr = inet_addr(argv[1]); 35 serveraddr.sin_port = htons(atoi(argv[2])); 36 37 tv.tv_sec = 5; 38 tv.tv_usec = 0; 39 if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, optlen) < 0) 40 err_log("fail to setsockopt"); 41 42 if(bind(sockfd, (struct sockaddr*)&serveraddr, sizeof(serveraddr)) < 0) 43 err_log("fail to bind"); 44 45 if(listen(sockfd, 5) < 0) 46 err_log("fail to listen"); 47 48 if((connectfd = accept(sockfd, (struct sockaddr*)&clientaddr, &len)) < 0) 49 { 50 if(errno == 11) 51 { 52 printf("errno = %d--->%s ", errno, strerror(errno)); 53 } 54 else 55 { 56 err_log("fail to accept"); 57 } 58 } 59 printf("client:%s--->%d ", inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port)); 60 while(1) 61 { 62 if(recv(connectfd, buf, N, 0) < 0) 63 err_log("fail to recv"); 64 if(strncmp(buf, "quit", 4) == 0) 65 break; 66 buf[strlen(buf) - 1] = '