• TCP之非阻塞connect和accept


    套接字的默认状态是阻塞的,这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待响应操作完成,可能阻塞的套接字调用可分为以下四类:

    (1) 输入操作,包括read,readv,recv,recvfrom,recvmsg;

    (2) 输出操作,包括write,writev,send,sendto,sendmsg;

    (3) 接受外来连接,即accept函数。

    (4) 发起外出连接,即tcp的connect函数;

    非阻塞connect:

    当一个非阻塞的tcp套接字上调用connect时,connect将立即返回一个EINPROGRESS错误,不过已经发起的tcp三路握手继续进行。我们接着使用select检测这个连接或成功或失败的已建立条件。非阻塞connect有三个用途:

    (1) 我们可以把三路握手叠加在其他处理上,完成一个connect要花的RTT时间,而RTT波动很大,从局域网上的几毫秒到几百毫秒甚至是广域网的几秒。这段时间内也许有我们想要执行的其他工作可执行;

    (2) 我们可以使用这个技术同时建立多个连接;这个技术随着web浏览器流行起来;

    (3) 既然使用select等待连接建立,我们可以给select指定一个时间限制,使得我们能够缩短connect的超时。

    非阻塞connect细节:

    (1) 尽管套接字是非阻塞的,如果连接到的服务器在同一个主机上,那么当我们调用connect时候,连接通常立刻建立,我们必须处理这种情形;

    (2) 源自Berkeley的实现(和posix)有关select和非阻塞connect的以下两个原则:

    --(a) 当连接成功建立时,描述符变为可写;

    --(b) 当连接建立遇到错误时,描述符变为既可读又可写;

    非阻塞accept:

    在比较忙的服务器中,在建立三次握手之后,调用accept之前,可能出现客户端断开连接的情况,再这样的情况下;如,三次握手之后,客户端发送rst,然后服务器调用accept。posix指出这种情况errno设置为CONNABORTED;

    注意Berkeley实现中,没有返回这个错误,而是EPROTO,同时完成三次握手的连接会从已完成队列中移除;在这种情况下,如果我们用select监听到有新的连接完成,但之后又被从完成队列中删除,此时如果调用阻塞accept就会产生阻塞;

    解决办法:

    (1) 使用select监听套接字是否有完成连接的时候,总是把这个监听套接字设置为非阻塞;

    (2) 在后续的accept调用中忽略以下错误,EWOULDBLOCK(Berkeley实现,客户中止连接), ECONNABORTED(posix实现,客户中止连接), EPROTO(serv4实现,客户中止连接)和EINTR(如果有信号被捕获);

  • 相关阅读:
    有一种努力叫“凌晨四点”
    编程思想
    小记
    团队精神与集体主义
    变量起名
    软件项目估量方法
    戏说QQ
    压力说
    AngularJS指令基础(一)
    Leetcode 1021. Best Sightseeing Pair
  • 原文地址:https://www.cnblogs.com/wanpengcoder/p/5358259.html
Copyright © 2020-2023  润新知