socket超时linux,Linux下的socket编程实践(五)设置套接字I/O超时的方案

gcc g++现在是gnu中最主要和最流行的c c++编译器 。g++是c++的命令,以.cpp为主,对于c语言后缀名一般为.c。这时候命令换做gcc即可。其实是无关紧要的。其实编译

14ab59739ac7c30303fbce244545985c.png

(一)使用alarm 函数设置超时

#include

unsigned int alarm(unsigned int seconds);

void sigHandlerForSigAlrm(int signo)

{

return ;

}

signal(SIGALRM, sigHandlerForSigAlrm);

alarm(5);

int ret = read(sockfd, buf, sizeof(buf));

if (ret == -1 && errno == EINTR)

{

// 阻塞并且达到了5s,超时,设置返回错误码

errno = ETIMEDOUT;

}

else if (ret >= 0)

{

// 正常返回(没有超时), 则将闹钟关闭

alarm(0);

}

如果read一直处于阻塞状态被SIGALRM信号中断而返回,则表示超时,否则未超时已读取到数据,取消闹钟。但这种方法不常用,因为有时可能在其他地方使用了alarm会造成混乱。

调用setsockopt设置读/写超时时间

/示例: read超时

int seconds = 5;

if (setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, &seconds, sizeof(seconds)) == -1)

err_exit("setsockopt error");

int ret = read(sockfd, buf, sizeof(buf));

if (ret == -1 && errno == EWOULDBLOCK)

{

// 超时,被时钟信号打断

errno = ETIMEDOUT;

} SO_RCVTIMEO是接收超时,SO_SNDTIMEO是发送超时。这种方式也不经常使用,因为这种方案不可移植,并且有些套接字的实现不支持这种方式。

(三)使用select函数实现超时

#include

int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,struct timeval *timeout);

struct timeval{

long tv_sec; /*秒 */

long tv_usec; /*微秒 */

}

select函数是在linux编程中很重要的一个函数,他有很多的功能,控制读、写、异常的集合,当然还有设置超时。

下面我们依次封装read_timeout、write_timeout、accept_timeout、connect_timeout四个函数,来了解select在超时设置方面的使用。

1.read_timeout

/**

*read_timeout - 读超时检测函数, 不包含读操作

*@fd: 文件描述符

*@waitSec: 等待超时秒数, 0表示不检测超时

*成功(未超时)返回0, 失败返回-1, 超时返回-1 并且 errno = ETIMEDOUT

**/

int read_timeout(int fd, long waitSec)

{

int returnValue = 0;

if (waitSec > 0)

{

fd_set readSet;

FD_ZERO(&readSet);

FD_SET(fd,&readSet); //添加

struct timeval waitTime;

waitTime.tv_sec = waitSec;

waitTime.tv_usec = 0;

//将微秒设置为0(不进行设置),如果设置了,时间会更加精确

do

{

returnValue = select(fd+1,&readSet,NULL,NULL,&waitTime);

}

while(returnValue < 0 && errno == EINTR); //等待被(信号)打断的情况, 重启select

if (returnValue == 0) //在waitTime时间段中一个事件也没到达,超时

{

returnValue = -1; //返回-1

errno = ETIMEDOUT;

}

else if (returnValue == 1) //在waitTime时间段中有事件产生

returnValue = 0; //返回0,表示成功

// 如果(returnValue == -1) 并且 (errno != EINTR), 则直接返回-1(returnValue)

}

return returnValue;

}

fd_set rset;

int fd;

FD_ZERO(&rset);

FD_SET(fd, &rset);

FD_SET(stdin, &rset);

if(FD_ISSET(fd, &rset)

{ ... }

2.write_timeout

实现方式和read_timeout基本相同。

/**

*write_timeout - 写超时检测函数, 不包含写操作

*@fd: 文件描述符

*@waitSec: 等待超时秒数, 0表示不检测超时

*成功(未超时)返回0, 失败返回-1, 超时返回-1 并且 errno = ETIMEDOUT

**/

int write_timeout(int fd, long waitSec)

{

int returnValue = 0;

if (waitSec > 0)

{

fd_set writeSet;

FD_ZERO(&writeSet);

//清零

FD_SET(fd,&writeSet); //添加

struct timeval waitTime;

waitTime.tv_sec = waitSec;

waitTime.tv_usec = 0;

do

{

returnValue = select(fd+1,NULL,&writeSet,NULL,&waitTime);

} while(returnValue < 0 && errno == EINTR); //等待被(信号)打断的情况

if (returnValue == 0) //在waitTime时间段中一个事件也没到达

{

returnValue = -1; //返回-1

errno = ETIMEDOUT;

}

else if (returnValue == 1) //在waitTime时间段中有事件产生

returnValue = 0; //返回0,表示成功

}

return returnValue;

} 3.accept_timeout

/**

*accept_timeout - 带超时的accept

*@fd: 文件描述符

*@addr: 输出参数, 返回对方地址

*@waitSec: 等待超时秒数, 0表示不使用超时检测, 使用正常模式的accept

*成功(未超时)返回0, 失败返回-1, 超时返回-1 并且 errno = ETIMEDOUT

**/

int accept_timeout(int fd, struct sockaddr_in *addr, long waitSec)

{

int returnValue = 0;

if (waitSec > 0)

{

fd_set acceptSet;

FD_ZERO(&acceptSet);

FD_SET(fd,&acceptSet); //添加

struct timeval waitTime;

waitTime.tv_sec = waitSec;

waitTime.tv_usec = 0;

do

{

returnValue = select(fd+1,&acceptSet,NULL,NULL,&waitTime);

}

while(returnValue < 0 && errno == EINTR);

if (returnValue == 0) //在waitTime时间段中没有事件产生

{

errno = ETIMEDOUT;

return -1;

}

else if (returnValue == -1) // error

return -1;

}

/**select正确返回:

表示有select所等待的事件发生:对等方完成了三次握手,

客户端有新的链接建立,此时再调用accept就不会阻塞了

*/

socklen_t socklen = sizeof(struct sockaddr_in);

if (addr != NULL)

returnValue = accept(fd,(struct sockaddr *)addr,&socklen);

else

returnValue = accept(fd,NULL,NULL);

return returnValue;

}

4.connect_timeout

(1)我们为什么需要这个函数?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值