listen()函数中backlog参数分析

来源:互联网 发布:exec linux脚本 用法 编辑:程序博客网 时间:2024/06/05 08:20

背景知识

Unix网络编程描述如下:



总结

0. accept()函数不参与三次握手,而只负责从已建立连接队列中取出一个连接和sockfd进行绑定;
1. backlog参数决定了未完成队列和已完成队列中连接数目之和的最大值(从内核角度看,是否这个和就是等于sock->recv_queue ?);
2. accept()函数调用,会从已连接队列中取出一个“连接”(可以是一个描述连接的数据结构,listensocket->sock->recv_queue[sk_buff] ? ),未完成队列和已完成队列中连接数目      之和将减少1;即accept将监听套接字对应的sock的接收队列中的已建立连接的sk_buff取下(从该sk_buff中可以获得对端主机的发送过来的tcp/ip数据包)
3. 监听套接字的已完成队列中的元素个数大于0,那么该套接字是可读的。
4. 当程序调用accept的时候(设置阻塞参数),那么判定该套接字是否可读,不可读则进入睡眠,直至已完成队列中的元素个数大于0(监听套接字可读)而唤起监听进程。


实例分析1

将服务器端的listen函数backlog设置为2,用20个客户端与服务器建立连接,查看连接的建立情况。

服务器代码:

#include <stdio.h>#include<unistd.h>#include<sys/types.h>       /* basic system data types */#include<sys/socket.h>      /* basic socket definitions */#include<netinet/in.h>      /* sockaddr_in{} and other Internet defns */#include<arpa/inet.h>       /* inet(3) functions */#include<sys/epoll.h>       /* epoll function */#include<fcntl.h>#include<stdlib.h>#include<errno.h>#include<stdio.h>#include<string.h>int main(int argc,char*argv[]){    int listenfd,connfd;    struct sockaddr_in cliaddr,servaddr;    int queuelen=5;    if(argc!=2){        puts("usage# ./aworker listenqueuelen");        exit(0);    }       queuelen=atoi(argv[1]);    listenfd = socket(AF_INET,SOCK_STREAM,0);    bzero(&servaddr,sizeof(servaddr));    servaddr.sin_family = AF_INET;    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);    servaddr.sin_port = htons(2989);        bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));        listen(listenfd,queuelen);    sleep(60); //将这个注释,会出现另一种情况哟~~      while(1)    {        connfd = accept(listenfd,NULL,0);        if(connfd == -1)        {            perror("accept error");            continue;        }        puts("new connection...");    }    return 0;}

client代码

#include "client.h"//void cli_hander(int sockfd,)int main(){    int sockfd;    int rc;     int cpid;    struct sockaddr_in servaddr;        bzero(&servaddr,sizeof(servaddr));    servaddr.sin_family = AF_INET;    inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);    servaddr.sin_port = htons(2989);        for(int i=0;i<20;i++)    {           cpid = fork();        if(cpid == 0)        {               sockfd = socket(AF_INET,SOCK_STREAM,0);            rc = connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));            if(rc == -1)             {                   perror("connect error");                exit(0);            }               printf("pid#%d connected...\n",getpid());            sleep(3);            close(sockfd);            exit(0);        }       }       while(1)    {           cpid = wait(NULL);        if(cpid==-1){            perror("end of wait");            break;        }        printf("pid#%d exit...\n",cpid);    }    return 0;}

实验结果:

服务器端显示:

root@cloud2:~/slp/NetWrokProgram/server# ./aworker 2new connection...new connection...new connection...new connection...new connection...

客户端显示:

root@cloud2:~/slp/NetWrokProgram/client# ./a.out pid#16697 connected...pid#16699 connected...pid#16698 connected...pid#16697 exit...pid#16699 exit...pid#16698 exit...pid#16700 connected...pid#16701 connected...pid#16700 exit...pid#16701 exit...connect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outconnect error: Connection timed outpid#16702 exit...pid#16703 exit...pid#16704 exit...pid#16705 exit...pid#16706 exit...pid#16707 exit...pid#16708 exit...pid#16709 exit...pid#16710 exit...pid#16711 exit...pid#16712 exit...pid#16713 exit...pid#16714 exit...pid#16715 exit...pid#16716 exit...end of wait: No child processes

结果分析:

同时建立连接的客户端进程共有20个,可是只有5个完成了连接的建立,其他15个没有成功。有趣的是,建立的5个链接中有3个是马上建立的,2个是过了一段时间后后来才建立的。

实例分析2

将server端的代码中的sleep(60)注释,即服务端listen即开始进入while循环中的accept阻塞:

    ...    listen(listenfd,queuelen);    sleep(60); //将这个注释,会出现另一种情况哟~~      while(1)    {        connfd = accept(listenfd,NULL,0);        ....

同样的运行,结果如下:

root@cloud2:~/slp/NetWrokProgram/server# ./aworker 2new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...new connection...

客户端:
root@cloud2:~/slp/NetWrokProgram/client# ./a.out pid#16736 connected...pid#16737 connected...pid#16738 connected...pid#16739 connected...pid#16740 connected...pid#16741 connected...pid#16742 connected...pid#16743 connected...pid#16744 connected...pid#16745 connected...pid#16746 connected...pid#16747 connected...pid#16748 connected...pid#16749 connected...pid#16750 connected...pid#16751 connected...pid#16752 connected...pid#16753 connected...pid#16755 connected...pid#16754 connected...pid#16736 exit...pid#16737 exit...pid#16738 exit...pid#16739 exit...pid#16740 exit...pid#16741 exit...pid#16742 exit...pid#16743 exit...pid#16744 exit...pid#16745 exit...pid#16746 exit...pid#16747 exit...pid#16748 exit...pid#16749 exit...pid#16750 exit...pid#16751 exit...pid#16752 exit...pid#16753 exit...pid#16755 exit...pid#16754 exit...end of wait: No child processes

结果分析:
由于每个连接在建立之后,已完成队列中的连接马上就被accept给读取了,所以已完成和未完成队列中的连接数之和根本不可能超过backlog限定的个数。

原文链接:
http://blog.csdn.net/ordeder/article/details/21551567

2 0
原创粉丝点击