linux非阻塞套接字的联机请求问题

在一个TCP套接口被设置为非阻塞之后调用connect,connect 会立即返回EINPROGRESS错误,表示连接操作正在进行中,但是仍未完成;同时TCP的三路握手操作继续进行;在这之后,我们可以调用select来检查这个链接是否建立成功。

非阻塞connect有三种用途:
1. 我们可以在三路握手的同时做一些其它的处理。connect 操作要花一个往返时间完成,而且可以是在任何地方,从几个毫秒的局域网到几百毫秒或几秒的广域网,在这段时间内我们可能有一些其他的处理想要执行;
2. 可以用这种技术同时建立多个连接.在Web浏览器中很普遍;
3. 由于我们使用select 来等待连接的完,因此我们可以给select设置一个时间限制,从而缩短connect 的超时时间。在大多数实现中,connect 的超时时间在75秒到几分钟之间。有时候应用程序想要一个更短的超时时间,使用非阻塞connect 就是一种方法。

非阻塞connect 听起来虽然简单,但是仍然有一些细节问题要处理:
1. 即使套接口是非阻塞的。如果连接的服务器在同一台主机上,那么在调用connect 建立连接时,连接通常会立即建立成功,我们必须处理这种情况。
2. 源自Berkeley的实现(和Posix.1g)有两条与select 和非阻塞IO相关的规则:
  A. 当连接建立成功时,套接口描述符变成可写;
  B. 当连接出错时,套接口描述符变成既可读又可写。

处理非阻塞connect的步骤(重点):
1. 创建socket,返回套接口描述符;
2. 调用fcntl 把套接口描述符设置成非阻塞;
3. 调用connect 开始建立连接;
4. 判断连接是否成功建立。

判断连接是否成功建立:
A. 如果connect 返回0,表示连接成功(服务器和客户端在同一台机器上时就有可能发生这种情况);
B. 调用select 来等待连接建立成功完成;
      如果select 返回0,则表示建立连接超时。我们返回超时错误给用户,同时关闭连接,以防止三路握手操作继续进行下去。
      如果select 返回大于0的值,则需要检查套接口描述符是否可写,如果套接口描述符可写,则我们可以通过调用getsockopt来得到套接口上待处理的错误(SO_ERROR)。如果连接建立成功,这个错误值将是0;如果建立连接时遇到错误,则这个值是连接错误所对应的errno值(比如:ECONNREFUSED,ETIMEDOUT等)。
这样就比较好理解了。


移植性问题总结(个人觉得下面移植问题可以忽略)
非阻塞connect 有这么多好处,但是处理非阻塞connect 时会遇到很多可移植性问题。
1. 对于出错的套接口描述符,getsockopt的返回值源自Berkeley的实现是返回0,待处理的错误值存储在errno中;而源自Solaris的实现是返回-1,待处理的错误存储在errno中。(套接口描述符出错时调用getsockopt的返回值不可移植)
2.有可能在调用select之前,连接就已经建立成功,而且对方的数据已经到来,在这种情况下,套接口描述符是既可读又可写。这与套接口描述符出错时是一样的。(怎样判断连接是否建立成功的条件不可移植)

在我们判断连接是否建立成功的条件不唯一时,我们可以有以下的方法来解决这个问题:
1. 调用getpeername代替getsockopt。如果调用getpeername失败,getpeername返回ENOTCONN,表示连接建立失败,我们必须以SO_ERROR调用getsockopt得到套接口描述符上的待处理错误;
2. 调用read,读取长度为0字节的数据。如果read调用失败,则表示连接建立失败,而且read返回的errno指明了连接失败的原因。如果连接建立成功,read应该返回0;
3. 再调用一次connect,它应该失败。如果错误errno是EISCONN,就表示套接口已经建立,而且第一次连接是成功的;否则,连接就是失败的。

被中断的connect
如果在一个阻塞式套接口上调用connect,在TCP的三路握手操作完成之前被中断了,比如说,被捕获的信号中断,将会发生什么呢?假定connect不会自动重启,它将返回EINTR。那么,这个时候我们就不能再调用connect等待连接建立完成了,如果再次调用connect来等待连接建立完成的话,connect将会返回错误值EADDRINUSE。在这种情况下,应该做的是调用select,就像在非阻塞式connect中所做的一样。然后,select在连接建立成功(使套接口描述符可写)或连接建立失败(使套接口描述符既可读又可写)时返回。

<完>

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值