您的位置:首页 > 理论基础 > 计算机网络

C/S 超时控制的几种写法

2018-02-17 08:27 295 查看
第一种:调用alarm(second)超时时,发送SIGALRM信号,产生中断.

实例:回显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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息