/*
测试伪代码
*/
int ret;
ret = read_timeout(fd,5);
if(ret == 0)
{
read(fd...)
}
else if(ret == -1 && errno == ETIMEDOUT)
{
timeout...
}
else
{
ERR_EXIT("read_timeout");
}
/*
读超时
*/
int read_timeout(int fd,unsigned int wait_seconds)
{
int ret=0;
if(wait_seconds > 0)
{
fd_set read_fdset;
struct timeval timeout;
FD_ZERO(&read_fdset);
FD_SET(fd,&read_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = 0;
do{
ret = select(fd+1,&read_fdset,NULL,NULL,&timeout); //写操作的化是把文件描述符放在写的集合
}while(ret < 0 && errno = EINTR);
if(ret == 0)
{
ret = -1;
errno = ETIMEDOUT;
}
else if(ret == 1)
{
ret = 0;
}
}
return ret;
}
/*
带超时的accept
addr 返回对方的地址
*/
int accept_timeout(int fd,struct sockaddr_in *addr,unsigned int wait_seconds)
{
int ret;
socklen_t addrlen = sizeof(struct sockaddr_in);
if(wait_seconds > 0)
{
fd_set accept_fdset;
struct timeval timeout;
FD_ZERO(&accept_fdset);
FD_SET(fd,&accept_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = wait_seconds;
do
{
ret = select(fd+1,&accept_fdset,NULL,NULL,&timeout);
}while(ret<0 && errno == EINTR);
if(ret == -1)
return -1;
else if(ret == 0)
{
errno = ETIMEDOUT;
return -1;
}
}
if(addr != NULL)
{
ret = accept(fd,(struct sockaddr*)addr,&addrlen);
}
else
{
ret = accept(fd,NULL,NULL);
}
if(ret == -1)
ERR_EXIT("accept");
return ret;
}
/*
连接超时
ESTABLISED状态是连接成功的
*/
void activate_monblock(int fd)//将文件描述符设置成非阻塞模式
{
int ret;
int flags = fcntl(fd,F_GETFL);
if(flags == -1)
ERR_EXIT("fcntl");
flags |= O_NONBLOCK; // 变成阻塞 flags ~= O_NONBLOCK
ret = fcntl(fd,F_SETFL,flags);
if(ret == -1)
ERR_EXIT("fcntl");
}
int connect_timeout(int fd,struct sockaddr_in *addr,unsigned int wait_seconds)
{
int ret;
socklen_t addrlen = sizeof(struct sockaddr_in);
if(wait_seconds > 0)
activate_monblock(fd);
ret = connect(fd,(struct sockaddr*)addr,addrlen);
if(ret < 0 && errno == EINPROGRESS)
{
fd_set connect_fdset;
struct timeval_timeout;
FD_ZERO(&connect_fdset);
FD_SET(fd,&connect_fdset);
timeout.tv_sec = wait_seconds;
timeout.tv_usec = 0;
do
{
/*连接建立,套接字可写*/
ret = select(fd+1,NULL,&connect_fdset,NULL,&timeout);
}while(ret < 0 && errno = EINTR); //信号中断返回
if(ret == 0)
{
ret = -1;
errno = ETIMEDOUT;
}
else if(ret < 0)
{
return -1;
}
else if(ret == 1)
{
/*ret返回1,可能有两种情况,一种是连接建立成功,一种是套接字产生错误
此时的错误信息不会被储存在errno中,因此需要调用getsockopt来获取。
*/
int err;
socklen_t socklen = sizeof(err);
int sockoptret = setsockopt(fd,SOL_SOCKET,SO_ERROR,&on,&socklen);
if(sockoptret == -1)
return -1;
if(err == 0)
ret = 0;
else
{
errno = err;
ret = -1;
}
}
}
if(wait_seconds > 0)
{
//在套接口变成阻塞模式
}
return ret;
}
本文由 Ryan 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
2018/10/21 22:29