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

第一种:调用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;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值