一、使用SIGALRM爲connect 設置超時
signal 捕捉到alarm信號之後會中斷connect函數,導致返回值爲EINTR,因此可提前設置connect超時返回,而不用等到最長 75s的connect原始超時時長
1、Signal 返回值 爲 typede void Sigfunc(int); -- 可以保存和恢復舊的信號處理函數
2、alarm(); 可覆蓋之前的定時,返回值爲 之前定時的剩餘時間,返回0表示之前未設置定時
3、connect() 返回 < 0,設置爲失敗,超時; 若成功, == 0;connect失敗後需關閉close(sockfd);並重新 socket() 獲取套接字
/* include connect_timeo */
#include "unp.h"
static void connect_alarm(int);
int
connect_timeo(int sockfd, const SA *saptr, socklen_t salen, int nsec)
{
Sigfunc *sigfunc;
int n;
sigfunc = Signal(SIGALRM, connect_alarm);
if (alarm(nsec) != 0)
err_msg("connect_timeo: alarm was already set");
if ( (n = connect(sockfd, saptr, salen)) < 0) {
close(sockfd);
if (errno == EINTR)
errno = ETIMEDOUT;
}
alarm(0); /* turn off the alarm */
Signal(SIGALRM, sigfunc); /* restore previous signal handler */
return(n);
}
static void
connect_alarm(int signo)
{
return; /* just interrupt the connect() */
}
/* end connect_timeo */
void
Connect_timeo(int fd, const SA *sa, socklen_t salen, int sec)
{
if (connect_timeo(fd, sa, salen, sec) < 0)
err_sys("connect_timeo error"); // 出錯或者超時 都 < 0
// 連接成功 connect_timeo 返回 0
}
二、使用select爲accept 設置超時
fd_set fdset;
struct timeval tv;
FD_ZERO(&fdset);
FD_SET(info->sockfd, &fdset);
tv.tv_sec = 9;
tv.tv_usec = 0;
iRet = select(info->sockfd + 1, &fdset, NULL, NULL, &tv);
if (iRet > 0)
{
/*成功則爲非負描述符*/
connfd = accept(info->sockfd, (struct sockaddr *)&cliAddr, &iAddrLen);
if (connfd < 0)
{
printf("[%s %d] accept failed. \r\n", __FILE__, __LINE__);
return -1;
}
else
{
info->connfd = connfd;
printf("[%s %d] accept succ. connfd = %d\r\n", __FILE__, __LINE__, connfd);
return 0;
}
}
else
{
printf("[%s %d] select timeout or Failed\r\n", __FILE__, __LINE__);
return -1;
}
三、使用setsockopt設置SO_RCVTIMEO爲recvfrom設置超時
errno == EWOULDBLOCK
#include "unp.h"
void
dg_cli(FILE *fp, int sockfd, const SA *pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
struct timeval tv;
tv.tv_sec = 5;
tv.tv_usec = 0;
Setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv));
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen);
n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
if (n < 0) {
if (errno == EWOULDBLOCK) {
fprintf(stderr, "socket timeout\n");
continue;
} else
err_sys("recvfrom error");
}
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}