87-非阻塞 connect
非阻塞i/o 上调用 connect 比非阻塞 i/o 上调用 read/write 要麻烦一点,一方面 connect 函数不能像 read/write 那样反复调用,它只能调用一次;另一方面,connect 函数返回错误,并不代表连接建立不成功。
1. 非阻塞 connect
对于 TCP 协议,在非阻塞 i/o 上调用 connect,意味着 connect 会发送 SYN 段给服务器:
- 如果在 connect 返回时,收到了服务器的 ACK,则 connect 返回 0,意味着连接建立成功,这通常只会发生在本机连接上。
- 如果在 connect 返回时,未收到服务器的 ACK,则 connect 返回 -1,同时 errno 置为 EINPROGRESS,这个错误表示“正在进行……”.
- 如果 connect 返回错误,errno 不是 EINPROGRESS 可以立即判断连接建立失败。
1.1 如何判断连接成功或失败?
对于 TCP 连接:
- 连接建立成功:套接字描述符可写。
- 连接建立失败:套接字描述符可读可写。
注1:上面说的可读可写的含义是 select 函数返回的读集合和写集合是否存在这个描述符。若描述符在读集合里,说明可读;如果在写集合里,说明可写。
注2:一般来说,新创建的描述符,在执行 connect 前既不可读也不可写,连接成功后,则变得可写(这是一定的),但是不一定可读。如果新创建的描述符变得可读了,大概率意味着出错,因为错误是通过 read 系统调用间接返回的。
根据上面两条规则,我们可以使用 select 来处理这两种情况。事先建立读写集合,然后使用 select 监听。
但是,反过来根据套接字描述符可读可写来判断连接成功是不可行的。换句话说,下面这样做是不对的:
- 如果可写不可读:连接建立成功(可以这样判断)
- 如果可写可读:连接建立失败(不可以这样判断)
原因很简单,可写可读,并不一定就是失败,也许是对端发来数据了呢?所以,得使用另外一种办法来判断——使用套接字选项 SO_ERROR. 这也是 SO_ERROR 极少能派上用场的地方之一。
只要套接字描述符变得可读或可写,直接使用 getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len)
取得套接字的状态。
注意:不同版本实现 getsockopt 行为有差异。如果真的产生错误:
- Berkeley 实现让 getsockopt 返回 0,同时 error 中保存错误码(linux 也是这样的)
- Solaris 实现让 getsockopt 返回 -1,同时 errno 中保存错误码(不是 error 参数)
1.2 伪代码
int nbioConnect(int sockfd, sockaddr *addr, socklent_t addrlen, int nsec) {int ret, error;socklent_t len;fd_set rfds, wfds;setNonblock(sockfd, 1); // 设置为非阻塞error = 0;// 发起连接ret = connect(sockfd, addr, addrlen);if (ret < 0) {if (errno != EINPROGRESS) {// 立即返回错误。close(sockfd);return -1;}}else if (ret == 0) {// 这种一般出现在本机连接上setNonblock(sockfd, 0); // 重新设置为阻塞return 0;}rfds = {sockfd};wfds = {sockfd};tv.tv_sec = nsec;tv.tv_usec = 0;// 在连接建立成功或失败前,或者超时时间未到,select 是不会返回的。ret = select(sockfd + 1, &rfds, &wfds, NULL, nsec ? &tv : NULL);if (ret < 0) {// 小概率事件close(sockfd);return -1;}else if (ret == 0) {// 超时errno == ETIMEDOUT;close(sockfd);return -1;}// 如果执行到这里了,说明连接已经建立成功或者失败,也就是说套接字描述符一定是可写或可读的或两者兼有。if (FD_ISSET(sockfd, &rfds) || FD_ISSET(sockfd, &wfds)) {// 这个 if 判断显的多余len = sizeof(error);ret = getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, &len);if (ret < 0) {// Solaris 版本可能会发生这种情况close(sockfd);return -1;}}if (error) {// Linux 版本如果错误会执行到这里errno = error;close(sockfd);return -1;}setNonblock(sockfd, 0); return 0;
}
2. 实验
这一次,只是将上篇写的时间获取客户端中的 connect 函数修改为了 nbioConnect 函数,并添加了一个超时参数进行控制。
- 程序路径
本文使用的程序托管在 gitos 上:http://git.oschina.net/ivan_allen/unp
如果你已经 clone 过这个代码了,请使用 git pull
更新一下。本节程序所使用的程序路径是 unp/program/nonblockio/nbiotimecli
.
- 实验结果
图1 设置超时时间为 10 s,结果超时
图2 连接成功
3. 总结
- 掌握非阻塞 i/o 上调用 connect 函数
- 知道如何判断非阻塞 connect 函数调用成功还是失败
87-非阻塞 connect相关推荐
- 【网络编程】非阻塞connect详解
一.为什么使用非阻塞connect TCP连接的建立涉及一个在三路握手过程,阻塞的connect一直等到客户收到自己的SYN的ACK才返回,这需要至少一个RTT时间,RTT时间波动很大从几毫秒到几秒. ...
- 网络编程学习笔记(非阻塞connect)
设置非阻塞,如果返回EINPROGRESS,表示正在建立连接,还没有完成 非阻塞的三个用途: 1.我们可以在三路握手的同时做其它的处理.connect要花一个往返时间完成,而且可以是在任何地主,从几个 ...
- 非阻塞connect的实现
步骤1: 设置非阻塞,启动连接 实现非阻塞 connect ,首先把 sockfd 设置成非阻塞的.这样调用 connect 可以立刻返回,根据返回值和 errno 处理三种情况: (1) 如果返回 ...
- linux下网络编程设置非阻塞,UNIX网络编程 非阻塞connect的实现
一.<UNIX网络编程>-非阻塞connect 在一个TCP套接口被设置为非阻塞之后调用connect,connect会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未 ...
- 由select/epoll返回的非阻塞connect还会是EINPROGRESS状态吗?
一般情况下,我们像下面代码中所示的这样使用非阻塞connect: #include <stdio.h> #include <stdlib.h> #include <str ...
- linux网络编程-----非阻塞connect
libevent在内部由于使用io多路复用函数进行的事件监控,所以它所有的io读写操作都是非阻塞的,换句话说,libevent提供的接口函数evconnlistener_new_bind()和buff ...
- 非阻塞connect
在 socket 是阻塞模式下 connect 函数会一直到有明确的结果才会返回(或连接成功或连接失败),如果服务器地址"较远",连接速度比较慢,connect 函数在连接过程中可 ...
- Linux高性能服务器I/0高级应用:非阻塞connect(15)
前言 首linux系统下,connect函数是阻塞的,阻塞时间的长度与系统相关.而如果把套接字设置成非阻塞,调用connect函数时会报错Operation now in progress,且errn ...
- Linux 非阻塞connect,错误码:EINPROGRESS
当我们以非阻塞的方式来进行连接的时候,返回的结果如果是 -1,这并不代表这次连接发生了错误,如果它的返回结果是 EINPROGRESS,那么就代表连接还在进行中. 后面可以通过poll或者select ...
- 非阻塞connect,错误码:EINPROGRESS
当我们以非阻塞的方式来进行连接的时候,返回的结果如果是 -1,这并不代表这次连接发生了错误,如果它的返回结果是 EINPROGRESS,那么就代表连接还在进行中. 后面可以通过poll或者select ...
最新文章
- mysql ls命令,Linux 常用 ls命令详解
- 七秘诀工作效率与薪水翻番-转
- 我的R之路:参数假设检验
- python企业级框架_Python六大开源框架对比:Web2py略胜一筹
- 从字到词,大词典中文BERT模型的探索之旅
- 如何将git分支上的标记移动到其他提交?
- 利用ModelBinder防止XSS一次尝试
- 【转】使用AIDL实现进程间的通信之复杂类型传递
- Redis基础、应用场景、数据结构及案例
- Allegro走等长线设置
- c语言保留三位小数用float,float保留三位小数
- CentOS7 WordPress无法将上传的文件移动至wp-content/uploads/ ApacheNginx解决方案
- C# 创建桌面快捷方式
- 如何查看自己的外网 IP 地址
- uniapp微信小程序授权登录和获取微信绑定的手机号码
- 红米ac2100有ipv6吗_Redmi路由器AC2100开箱:六天线简单直接,功能丰富对玩家友好...
- 企业如何借助工具分析用户画像
- 计算相似度的LLR算法
- vue使用腾讯地图定位以及地图组件使用
- WebStorm license server