网络编程之listen函数

基本TCP客户端/服务器程序的套接字函数


listen函数仅由TCP服务调用,它做两件事

    1.当socket函数创建一个套接字时,它被假设为一个主动套接字,也就是说,它是一个将调用connect连接的客户套接字。listen函数把一个未连接的套接字转换成一个被动套接字,指示内核应该接受指向该套接字的连接请求。如下图所示,调用listen导致套接字从CLOSED状态转换到LISTEN状态。

    2.listen函数的第二个参数规定了内核应为相应套接字排队的最大连接个数。

        #include<sys/socket.h>

        int listen(int sockfd, int backlog);

    本函数通常应该在调用socketbind之后,并在调用accept之前被调用。

    为了理解其中的backlog参数,我们必须认识到内核为任何一个给定的监听套接字维护两个队列:

    (1)未完成连接队列,每个这样的SYN分节对应其中的一项:已由某个客户发出并到达服务器,而服务器正在等待完成相应的TCP三路握手过程。这些套接字处于SYN_RCVD状态,如上图。

    (2)已完成连接队列,每个已完成TCP三路握手过程的客户对应其中一项。这些套接字处于ESTABLISHED状态。

下图描绘了监听套接字的这两个队列


    每当在未完成连接队列中创建一项时,来自监听套接字的参数就复制到即将建立的连接中。连接的创建机制是完全自动的,无需服务器进程插手。下图展示了两个队列建立连接时所交换的分组:


    当来自客户的SYN到达时,TCP在未完成连接队列中创建一个新项,然后响应以三路握手的第二个分节:服务器的SYN响应,其中捎带对客户SYN的ACK。这一项一直保留在未完成连接队列中,直到三路握手的第三个节点到达或者该项超时为止。如果三次握手正常完成,该项就从未完成连接队列移到已完成连接队列的队尾。当进程调用accept时,已完成连接队列中的对头将返回给进程,或者如果队列为空,那么进程将被投入睡眠,直到TCP在该队列中放入一项才唤醒它。

    关于这两个队列的处理,以下几点需要考虑:

  • listen函数的backlog参数曾被规定为这两个队列总和的最大值
  • 源自Berkeley的实现给backlog增设了一个模糊因子:把它乘以1.5得到的未处理队列最大长度。举例来说,通常指定为5的backlog值实际上允许最多有8项在排队。
  • 不要把backlog设为0,因为不同的实现对此有不同的解释(下方图4-10)。如果你不想让任何客户连接到你的监听套接字上,那就关掉该坚挺套接字。
  • 在三路握手正常完成的前提下,未完成连接队列中的任何一项在其中的存留时间就是一个RTT,而RTT的值取决于特定的客户与服务器。
  • 历来沿用的样例代码总是给出值为5的backlog,因为这是BSD4.2支持的最大值。这个值在20世纪八十年代是足够的,当时繁忙的服务器一天也就处理几百个连接。然而随着万维网的发展,繁忙的服务器一天要处理几百万个连接,这个偏小的值就根本不够了。繁忙的HTTP服务器必须指定一个较大的backlog值,而且较新的内核必须支持较大的backlog值

                当前许多系统允许管理员修改backlog的最大值

  • 问题是既然backlog的值为5不合适,那么该指定多少呢?这个问题不好回答。当今的HTTP服务器指定了一个较大值,但是如果这个指定值在源码中是一个常量,那么增长其大小就要重新编译服务器程序。另一个方法就是设定一个默认值,允许通过命令行选项或环境变量覆写该默认值。指定一个比内核能够支持的值更大的backlog也是可以接受的,因为内核应该悄然把所指定的偏大值截成自身支持的最大值,而不返回错误。我们通过修改listen的包裹函数就能提供解决问题的一个简单办法,如下所示:我们允许环境变量LISTENQ覆写有调用者指定的值
int Listen(int sockfd, int backlog){
    char *ptr;

    if( (ptr = getenv("LISTENQ")) != NULL)
        backlog=atoi(ptr);
    if(listen(fd, backlog)<0)
        err_sys("listen error");
}

atoi可看这篇文章。



下图是7种操作系统对backlog的意义的解释的不同


  • 32
    点赞
  • 134
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值