C/S 超时控制的几种写法
2018-02-17 08:27
295 查看
第一种:调用alarm(second)超时时,发送SIGALRM信号,产生中断.
实例:回显C/S
服务端代码:
客户端代码:
第二种:采用轮询技术:
select + udp echo c/s:
服务端代码:
客户端代码:
第三种:为套接字设置SO_RCVTIMEO或SO_SNDTIMEO选项
服务端代码:
客户端代码:
实例:回显C/S
服务端代码:
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/wait.h> #include <signal.h> #include <netdb.h> #define BUFSIZE 4096 #define LISTENQ 100 void sig_child(int signo) { int ppid; while ((ppid = waitpid(-1,NULL,WNOHANG)) > 0) { printf("child: %d terminate\n",ppid); } } void sig_alarm(int signo) { return; } int tcp_send(int sockfd,char* buf,int len,int second) { struct sigaction oact,act; act.sa_handler = sig_alarm; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGALRM,&act,&oact) < 0) { printf("tcp_send: sigaction error: %s\n",strerror(errno)); exit(1); } if (alarm(second) != 0) { printf("tcp_send: already set alarm\n"); exit(1); } if (write(sockfd,buf,len) != len) { if (errno == EINTR) { errno = ETIMEDOUT; printf("tcp_send: send message to client timeout\n"); exit(1); } printf("write error: %s\n",strerror(errno)); exit(1); } alarm(0); if (sigaction(SIGALRM,&oact,NULL) < 0) { printf("tcp_send: sigaction error: %s\n",strerror(errno)); exit(1); } } void server_echo(int sockfd) { char recv[BUFSIZE]; int n; while ((n = read(sockfd,recv,BUFSIZE)) > 0) { //sleep(8); tcp_send(sockfd,recv,n,2); } } int main(int argc,char** argv) { if (argc != 2) { printf("please add <service name or port number>\n"); exit(1); } struct addrinfo hints; bzero(&hints,sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; struct addrinfo* results; int err; if ((err = getaddrinfo(NULL,argv[1],&hints,&results)) != 0) { printf("getaddrinfo error: %s\n",gai_strerror(err)); exit(1); } struct addrinfo* dummy = results; int sockfd; for (; dummy != NULL; dummy = dummy->ai_next) { if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) { continue; } if (bind(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) { break; } close(sockfd); } if (dummy == NULL) { freeaddrinfo(results); printf("all socket failed\n"); exit(1); } freeaddrinfo(results); if (listen(sockfd,LISTENQ) < 0) { printf("listen error: %s\n",strerror(errno)); exit(1); } if (signal(SIGCHLD,sig_child) == SIG_ERR) { printf("signal error: %s\n",strerror(errno)); exit(1); } int connfd; int pid; for (; ;) { if ((connfd = accept(sockfd,NULL,NULL)) < 0) { if (errno == EINTR) { continue; } printf("accept error: %s\n",strerror(errno)); exit(1); } if ((pid = fork()) < 0) { printf("fork error: %s\n",strerror(errno)); exit(1); }else if (pid == 0) { close(sockfd); server_echo(connfd); close(connfd); } close(connfd); } return 0; }
客户端代码:
#include <sys/socket.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <netdb.h> #include <signal.h> #define BUFSIZE 4096 static void sig_alarm(int signo) { return; } int tcp_connect(int sockfd,struct sockaddr* peer,socklen_t len,int second) { //成功返回 1 失败返回-1 超时返回0 int ret = 1; struct sigaction oact,act; act.sa_handler = sig_alarm; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGALRM,&act,&oact) < 0) { printf("tcp_connect: sigaction error: %s\n",strerror(errno)); exit(1); } if (alarm(second) != 0) { printf("tcp_connect: alarm error: alarm already set\n"); exit(1); } if (connect(sockfd,peer,len) < 0) { if (errno == EINTR) { errno = ETIMEDOUT; ret = 0; printf("tcp_connect: one connect timeout\n"); }else { ret = -1; } } alarm(0); if (sigaction(SIGALRM,&oact,NULL) < 0) { printf("tcp_connect: sigaction error: %s\n",strerror(errno)); exit(1); } return ret; } int tcp_recv(int sockfd,char* buf,int second) { struct sigaction oact,act; act.sa_handler = sig_alarm; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGALRM,&act,&oact) < 0) { printf("tcp_recv: sigaction error: %s\n",strerror(errno)); exit(1); } if (alarm(second) != 0) { printf("tcp_recv: alarm error: alarm already set\n"); exit(1); } int cread = -1; if ((cread = read(sockfd,buf,BUFSIZE)) < 0) { if (errno == EINTR) { errno = ETIMEDOUT; printf("tcp_recv: read error: recvive from server timeout\n"); }else { printf("tcp_recv: read error: %s\n",strerror(errno)); exit(1); } } alarm(0); if (sigaction(SIGALRM,&oact,NULL) < 0) { printf("tcp_recv: sigaction error: %s\n",strerror(errno)); exit(1); } return cread; } int main(int argc,char** argv) { if (argc != 3) { printf("please add <ip address or host-name> <service name or port>\n"); exit(1); } struct addrinfo hints; bzero(&hints,sizeof(struct addrinfo)); hints.ai_flags = AI_ALL; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; struct addrinfo* results; int err; if ((err = getaddrinfo(argv[1],argv[2],&hints,&results)) != 0) { printf("getaddrinfo error: %s\n",gai_strerror(err)); exit(1); } struct addrinfo* dummy = results; int sockfd; for (; dummy != NULL; dummy = dummy->ai_next) { if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) { continue; } if (tcp_connect(sockfd,dummy->ai_addr,dummy->ai_addrlen,5) > 0) { break; } close(sockfd); } if (dummy == NULL) { freeaddrinfo(results); printf("all connect failed\n"); exit(1); } freeaddrinfo(results); char send[BUFSIZE]; int n; while ((n = read(STDIN_FILENO,send,BUFSIZE)) > 0) { if (write(sockfd,send,n) != n) { printf("write error: %s\n",strerror(errno)); exit(1); } if ((n = tcp_recv(sockfd,send,20)) == 0) { printf("server is restart or closed\n"); exit(1); } if (write(STDIN_FILENO,send,n) != n) { printf("write error: %s\n",strerror(errno)); exit(1); } } return 0; }
第二种:采用轮询技术:
select + udp echo c/s:
服务端代码:
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <string.h> #include <errno.h> #include <netdb.h> #include <unistd.h> #define BUFSIZE 4096 int main(int argc,char** argv) { if (argc != 2) { printf("please check <service name or port>\n"); exit(1); } struct addrinfo hints; bzero(&hints,sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; struct addrinfo* results; int err; if ((err = getaddrinfo(NULL,argv[1],&hints,&results)) != 0) { printf("getaddrinfo error: %s\n",gai_strerror(errno)); exit(1); } struct addrinfo* dummy = results; int sockfd; for (; dummy != NULL; dummy = dummy->ai_next) { if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) { continue; } if (bind(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) { break; } close(sockfd); } if (dummy == NULL) { freeaddrinfo(results); printf("all failed\n"); exit(1); } freeaddrinfo(results); struct sockaddr_storage peer; char recv[BUFSIZE]; socklen_t len = sizeof(struct sockaddr_storage); int n; for (; ;) { if ((n = recvfrom(sockfd,recv,BUFSIZE,0,(struct sockaddr*)&peer,&len)) < 0) { printf("recvfrom error: %s\n",strerror(errno)); exit(1); } sleep(9); if (sendto(sockfd,recv,n,0,(struct sockaddr*)&peer,len) != n) { printf("sendto error: %s\n",strerror(errno)); exit(1); } } return 0; }
客户端代码:
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <netdb.h> #include <sys/select.h> #include <signal.h> #define BUFSIZE 4096 void sig_alarm(int signo) { return; } int udp_readable(int fd,int second,int usec) { fd_set fs; FD_ZERO(&fs); FD_SET(fd,&fs); struct timeval tv; tv.tv_sec = second; tv.tv_usec = usec; return select(fd + 1,&fs,NULL,NULL,&tv); } void client(int fd) { char send[BUFSIZE]; int n; int err; while ((n = read(STDIN_FILENO,send,BUFSIZE)) > 0) { if (write(fd,send,n) != n) { printf("write error: %s\n",strerror(errno)); exit(1); } if ((err = udp_readable(fd,5,20)) == 0) { printf("udp_read: timeout\n"); exit(1); }else if (err < 0) { printf("udp_read: select error\n"); exit(1); }else if (err > 0) { if ((n = read(fd,send,BUFSIZE)) < 0) { printf("read error: %s\n",strerror(errno)); exit(1); } } if (write(STDOUT_FILENO,send,n) != n) { printf("write error: %s\n",strerror(errno)); exit(1); } } } int udp_connect(int sockfd,struct addrinfo* to,int second) { struct sigaction oact,act; act.sa_handler = sig_alarm; sigemptyset(&act.sa_mask); act.sa_flags = 0; if (sigaction(SIGALRM,&act,&oact) < 0) { printf("udp_connect: sigaction error: %s\n",strerror(errno)); exit(1); } if (alarm(second) != 0) { printf("udp_connect: alarm alreay set\n"); exit(1); } int ret = 0; if (connect(sockfd,to->ai_addr,to->ai_addrlen) < 0) { if (errno == EINTR) { errno = ETIMEDOUT; printf("udp_connect: connect timeout\n"); ret = 1; }else { printf("udp_connect: connect error: %s\n",strerror(errno)); ret = -1; } } alarm(0); if (sigaction(SIGALRM,&oact,NULL) < 0) { printf("udp_connect:sigaction error: %s\n",strerror(errno)); exit(1); } return ret; } int main(int argc,char** argv) { if (argc != 3) { printf("please check <hostname or ip address> <service name or port>\n"); exit(1); } struct addrinfo hints; bzero(&hints,sizeof(struct addrinfo)); hints.ai_flags = AI_ALL; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_DGRAM; hints.ai_protocol = IPPROTO_UDP; struct addrinfo* results; int err; if ((err = getaddrinfo(argv[1],argv[2],&hints,&results)) != 0) { printf("getaddrinfo error: %s\n",gai_strerror(err)); exit(1); } struct addrinfo* dummy = results; int sockfd; for (; dummy != NULL; dummy = dummy->ai_next) { if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) { continue; } if (udp_connect(sockfd,dummy,5) == 0) { break; } close(sockfd); } if (dummy == NULL) { printf("all socket failed\n"); freeaddrinfo(results); exit(1); } client(sockfd); close(sockfd); return 0; }
第三种:为套接字设置SO_RCVTIMEO或SO_SNDTIMEO选项
服务端代码:
#include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <unistd.h> #include <netdb.h> #include <string.h> #include <errno.h> #include <netinet/sctp.h> #define SCTP_MAX_STREAM 20 #define LISTENQ 100 #define BUFSIZE 4096 int main(int argc,char** argv) { if (argc != 2) { printf("please add <service name or port>\n"); exit(1); } struct addrinfo hints; bzero(&hints,sizeof(struct addrinfo)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_SEQPACKET; hints.ai_protocol = IPPROTO_SCTP; struct addrinfo* results; int err; if ((err = getaddrinfo(NULL,argv[1],&hints,&results)) != 0) { printf("getaddrinfo error: %s\n",gai_strerror(err)); exit(1); } struct addrinfo* dummy = results; int sockfd; for (; dummy != NULL; dummy = dummy->ai_next) { if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) { continue; } if (bind(sockfd,dummy->ai_addr,dummy->ai_addrlen) == 0) { break; } close(sockfd); } if (listen(sockfd,LISTENQ) < 0) { printf("listen error: %s\n",strerror(errno)); exit(1); } struct sctp_initmsg sim; bzero(&sim,sizeof(struct sctp_initmsg)); sim.sinit_num_ostreams = SCTP_MAX_STREAM; if (setsockopt(sockfd,IPPROTO_SCTP,SCTP_INITMSG,&sim,sizeof(struct sctp_initmsg)) < 0) { printf("setsockopt error: %s\n",strerror(errno)); exit(1); } struct sctp_event_subscribe events; bzero(&events,sizeof(struct sctp_event_subscribe)); events.sctp_data_io_event = 1; if (setsockopt(sockfd,IPPROTO_SCTP,SCTP_EVENTS,&events,sizeof(struct sctp_event_subscribe)) < 0) { printf("setsockopt error: %s\n",strerror(errno)); exit(1); } char recv[BUFSIZE]; int n; struct sctp_sndrcvinfo sri; struct sockaddr_storage peer; socklen_t len = sizeof(struct sockaddr_storage); int msg_flags; int stream_no = 0; for (; ;) { if ((n = sctp_recvmsg(sockfd,recv,BUFSIZE,(struct sockaddr*)&peer,&len,&sri,&msg_flags)) < 0) { printf("sctp_recvmsg error: %s\n",strerror(errno)); exit(1); } if (stream_no >= SCTP_MAX_STREAM) { stream_no = 0; } sleep(7); if (sctp_sendmsg(sockfd,recv,n,(struct sockaddr*)&peer,len,0,0,stream_no++,0,0) != n) { printf("sctp_sendmsg error: %s\n",strerror(errno)); exit(1); } } return 0; }
客户端代码:
#include <stdio.h> #include <stdlib.h> #include <netdb.h> #include <netinet/sctp.h> #include <sys/socket.h> #include <unistd.h> #include <string.h> #include <errno.h> #define BUFSIZE 4096 #define SCTP_MAX_STREAM 15 void client(int fd,struct sockaddr* to,socklen_t tolen) { char send[BUFSIZE]; int n; struct sctp_sndrcvinfo sri; int stream_num = 0; int msg_flags; struct timeval tv; tv.tv_sec = 5; tv.tv_usec = 20; if (setsockopt(fd,SOL_SOCKET,SO_RCVTIMEO,&tv,sizeof(struct timeval)) < 0) { printf("setsockopt error: %s\n",strerror(errno)); exit(1); } while ((n = read(STDIN_FILENO,send,BUFSIZE)) > 0) { if (stream_num >= SCTP_MAX_STREAM) { stream_num = 0; } if (sctp_sendmsg(fd,send,n,to,tolen,0,0,stream_num++,0,0) != n) { printf("sctp_sendmsg error: %s\n",strerror(errno)); exit(1); } if ((n = sctp_recvmsg(fd,send,BUFSIZE,NULL,NULL,&sri,&msg_flags)) < 0) { if (errno == EWOULDBLOCK) { printf("sctp_recvmsg: timeout\n"); exit(1); }else { printf("sctp_recvmsg error: %s\n",strerror(errno)); exit(1); } } printf("server peer stream_num: %d sctp_assoc_id %d\n",sri.sinfo_stream,sri.sinfo_assoc_id); if (write(STDOUT_FILENO,send,n) != n) { printf("write error: %s\n",strerror(errno)); exit(1); } } } int main(int argc,char** argv) { if (argc != 3) { printf("please check <host-name or ip address>\n"); exit(1); } struct addrinfo hints; bzero(&hints,sizeof(struct addrinfo)); hints.ai_flags = AI_ALL; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_SEQPACKET; hints.ai_protocol = IPPROTO_SCTP; struct addrinfo* results; int err; if (getaddrinfo(argv[1],argv[2],&hints,&results) != 0) { printf("getaddrinfo error: %s\n",gai_strerror(err)); exit(1); } int sockfd; struct addrinfo* dummy = results; sctp_assoc_t id; for (; dummy != NULL; dummy = dummy->ai_next) { if ((sockfd = socket(dummy->ai_family,dummy->ai_socktype,dummy->ai_protocol)) < 0) { continue; } struct sctp_initmsg sim; bzero(&sim,sizeof(struct sctp_initmsg)); sim.sinit_num_ostreams = SCTP_MAX_STREAM; if (setsockopt(sockfd,IPPROTO_SCTP,SCTP_INITMSG,&sim,sizeof(struct sctp_initmsg)) < 0) { close(sockfd); continue; } struct sctp_event_subscribe events; bzero(&events,sizeof(struct sctp_event_subscribe)); events.sctp_data_io_event = 1; if (setsockopt(sockfd,IPPROTO_SCTP,SCTP_EVENTS,&events,sizeof(struct sctp_event_subscribe)) < 0) { close(sockfd); continue; } if (sctp_connectx(sockfd,dummy->ai_addr,1,&id) == 0) { break; } close(sockfd); } if (dummy == NULL) { freeaddrinfo(results); printf("all failed\n"); exit(1); } client(sockfd,dummy->ai_addr,dummy->ai_addrlen); freeaddrinfo(results); close(sockfd); return 0; }
相关文章推荐
- Shell| 流程控制语句(if)和判断逻辑的几种写法(是否省略test)
- JAVA线程超时控制的几种方法
- asp.net MVC几种绑定下拉列表的写法
- 简述x264几种码率控制方式的实现
- Java for循环的几种写法
- 单列设计模式几种写法的比较
- jQuery 几种写法
- 【Java】迭代的几种控制方法
- HyperLink 控件控制图片宽度高度的几种方法
- 单例模式的几种写法
- 几种pc端页面 常用的js兼容ie写法,几个名词 nodeName nodeValue及value addEventListener attachEvent
- 单例模式的几种写法
- 几种简单的损坏控制文件的恢复方法
- 单例模式java中的几种写法和确保多线程下安全
- Git 忽略文件规则:.gitignore文件的几种写法
- “回”字有几种写法
- [导入]HyperLink 控件控制图片宽度高度的几种方法
- 用setsockopt()来控制recv()与send()的超时
- 函数返回值为字符串的几种写法
- 网卡速率变化导致paramiko模块timeout的失效,多线程超时控制解决办法。