一、SIGALRM超时超时接收问题
源代码片段:
#include "unp.h"
/*
* recvfrom with a Timeout Using SIGALRM
* */
void sig_alrm(int signo)
{
fprintf(stdout,"SIGALRM is OK\n");
return;
}
void do_cli(FILE *fp, int sockfd,
const struct sockaddr *pservaddr, socklen_t servlen)
{
int n;
char sendbuf[MAXLINE], recvbuf[MAXLINE];
socklen_t len;
while(Fgets(sendbuf, MAXLINE, fp) != NULL){
len = servlen;
Sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *) pservaddr, len);
Signal(SIGALRM, sig_alrm);
alarm(5);/*设置闹钟5s后, 将会产生SIGALRM信号,返回给系统*/
if((n = recvfrom(sockfd, recvbuf, MAXLINE, 0, NULL, NULL)) < 0){
if(errno == EINTR) fprintf(stderr, "socket timeout"); /*因为系统调用而中断*/
else{
fprintf(stdout, "recvfrom error");
}
}else{
alarm(0);
recvbuf[n] = 0; /* null terminate*/
Fputs(recvbuf, stdout);
}
}
}
代码分析:
1-10:设置信号处理函数,已中断被堵赛的recvfrom函数
22-37:设置信号SIGALRM的处理函数, 用alarm设置一个5s超时。当recvfrom堵塞5s后, recvfrom函数将会被系统处理函数中断, 返回-1, 进入信号处理函数。处理完毕以后,系统将会,查看errno的值,分析recvfrom中断原因。
29-最后:alarm(0)关掉闹钟警报。
编译运行结果如下:
二、Select分析超时接收问题
代码片段如下:
#include "unp.h"
/**
* recvfrom with a Timeout Using select
* */
int read_timeio(int fd, int sec)
{
fd_set rset;
FD_ZERO(&rset);
struct timeval tv;
tv.tv_sec = sec; /*设置秒*/
tv.tv_usec = 0; /*毫秒设置为0*/
FD_SET(fd, &rset);
return Select(fd + 1, &rset, NULL, NULL, &tv); /*利用select函数最后一个参数的特性,计时扫描。当返回0的时候,代表超时返回*/
}
void do_cli(FILE *fp, int sockfd,
const struct sockaddr *pservaddr, socklen_t servlen)
{
int n;
char sendbuf[MAXLINE], recvbuf[MAXLINE];
socklen_t len;
while(Fgets(sendbuf, MAXLINE, fp) != NULL){
len = servlen;
Sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *) pservaddr, len);
if(read_timeio(sockfd, 5) == 0){
fprintf(stderr, "socket timeout\n");
}else{
n = Recvfrom(sockfd, recvbuf, MAXLINE, 0, NULL, NULL);
recvbuf[n] = 0;
Fputs(recvbuf, stdout);
}
}
}
运行结果如下:
三、SO_RCVTIMEO套接字设置超时接收问题
#include "unp.h"
/*
* recvfrom with a Timeout Using SO_RCVTIMEO
* */
void do_cli(FILE *fp, int sockfd,
const struct sockaddr *pservaddr, socklen_t servlen)
{
int n;
char sendbuf[MAXLINE], recvbuf[MAXLINE];
socklen_t len;
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
Setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
while(Fgets(sendbuf, MAXLINE, fp) != NULL){
len = servlen;
Sendto(sockfd, sendbuf, strlen(sendbuf), 0, (struct sockaddr *) pservaddr, len);
if((n = recvfrom(sockfd, recvbuf, MAXLINE, 0, NULL, NULL)) < 0){
if(errno == EWOULDBLOCK) fprintf(stderr, "socket timeout");
else{
fprintf(stdout, "recvfrom error");
}
}else{
recvbuf[n] = 0; /* null terminate*/
Fputs(recvbuf, stdout);
}
}
}
分析如下:
13-15:首先初始化结构timeval中的时间,因为该套接字对应的(SOL_SOCKET SO_RCVTIMEO)的结构是struct timeval结构, 所以, 第四个参数的结构必须是struct timeval类型, 最后一个参数是 第四个参数的大小。
20-23:当io超时的时候, errno将会返回EWOULDBLOCK错误
服务端程序运行要求:通过睡眠5s后,才进行应答处理
运行结果如下: