socket使用非阻塞connect
2024-08-24 04:43:44
在使用tcp的connect调用时,默认是使用阻塞方式,当服务器当前不可用时,connect会等待(内部在重试?)直到超时时间到达,而这个超时时间是系统内核规定的,不能使用setSocketOpt来设置。
在碰到服务器不可用,上层逻辑进行重试时,如果超时时间过长,会产生卡死的感觉,用户体验也不佳,所以需要控制connect的超时时间。
参考网络上的资料,这里使用select。实现方式是:将socket设置为非阻塞方式,使用select来轮询socket,在select里指定超时时间,根据socket来判断连接状态。最后恢复socket的阻塞方式。
代码如下(linux):
int connect_with_timeout(int socket, const struct sockaddr *address, socklen_t address_len, int time_out)
{
int flag, old_flag;
old_flag = flag = fcntl(socket, F_GETFL, );
flag |= O_NONBLOCK;
fcntl(socket, F_SETFL, flag); int ret = -;
ret = ::connect(socket, (struct sockaddr*)address, address_len);
if (ret != ) {
if (errno != EINPROGRESS) {
LOG("connect failed,err(%d)", errno);
} else {
struct timeval tm;
tm.tv_sec = time_out;
tm.tv_usec = ;
fd_set set,rset;
FD_ZERO(&set);
FD_ZERO(&rset);
FD_SET(socket, &set);
FD_SET(socket, &rset); int res;
res = ::select(socket+, &rset, &set, NULL, &tm);
if (res < ) {
LOG("select:network error in connect.errno:%d", errno);
} else if(res == ) {
LOG("select:connect timeout.errno:%d", errno);
} else if (res == ) {
if (FD_ISSET(socket, &set)) {
LOG("select success");
ret = ;
}
} else {
LOG("other error when select: %s", strerror(errno));
}
}
} fcntl(socket, F_SETFL, old_flag); return ret;
}
::connect在非阻塞模式下会立即返回,如果没有其他错误,返回值等于0。
当::connect不能立即建立连接时,会返回EINPROGRESS,表示正在连接的过程中,这时可以使用select去轮询套接口,而select超时时间由参数指定 。
select返回值小于0,表明connect出错;等于0,表明connect超时;等于1,并且套接口的状态是可写,则表明connect已经成功建立。
最后恢复socket的阻塞属性。
参考:
http://olive101.blog.163.com/blog/static/2051263201011221915696/
最新文章
- 利用CSS背景颜色属性使父级div背景透明同时避免子级标签透明。
- 如何实现在PHP中调用JAVA
- HTML思维导图
- UIWindow 实现遮盖导航条的蒙版
- sql 查看 锁定的表 或者 未提交 的事务
- 论文阅读之 Inferring Analogous Attributes CVPR 2014
- Differences Between Xcode Project Templates for iOS Apps
- 重温《js权威指南》 第2-3章
- SQLServer处理亿万级别的数据的优化措施
- Android----二维码开发
- ETL构建数据仓库五步法
- Android学习----ADB
- datagrid指定行合并导出
- style-11bak
- Django unittest 单元测试
- python的对象 变量
- Oracle免安装绿色版-PLSQL连接报12154
- linux命令 xxd
- 微信小程序---获取上传图片大小
- 高可用Hadoop平台-集成Hive HAProxy