listen()函数中backlog 参数分析 深圳-燕情宝



总结

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个客户端与服务器建立连接,查看连接的建立情况。

服务器代码:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include <stdio.h>  
  2. #include<unistd.h>  
  3. #include<sys/types.h>       /* basic system data types */  
  4. #include<sys/socket.h>      /* basic socket definitions */  
  5. #include<netinet/in.h>      /* sockaddr_in{} and other Internet defns */  
  6. #include<arpa/inet.h>       /* inet(3) functions */  
  7. #include<sys/epoll.h>       /* epoll function */  
  8. #include<fcntl.h>  
  9. #include<stdlib.h>  
  10. #include<errno.h>  
  11. #include<stdio.h>  
  12. #include<string.h>  
  13.   
  14.   
  15. int main(int argc,char*argv[])  
  16. {  
  17.     int listenfd,connfd;  
  18.     struct sockaddr_in cliaddr,servaddr;  
  19.     int queuelen=5;  
  20.   
  21.     if(argc!=2){  
  22.         puts("usage# ./aworker listenqueuelen");  
  23.         exit(0);  
  24.     }     
  25.     queuelen=atoi(argv[1]);  
  26.   
  27.     listenfd = socket(AF_INET,SOCK_STREAM,0);  
  28.   
  29.     bzero(&servaddr,sizeof(servaddr));  
  30.     servaddr.sin_family = AF_INET;  
  31.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  32.     servaddr.sin_port = htons(2989);  
  33.       
  34.     bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));  
  35.       
  36.     listen(listenfd,queuelen);  
  37.     sleep(60); //将这个注释,会出现另一种情况哟~~    
  38.     while(1)  
  39.     {  
  40.         connfd = accept(listenfd,NULL,0);  
  41.         if(connfd == -1)  
  42.         {  
  43.             perror("accept error");  
  44.             continue;  
  45.         }  
  46.         puts("new connection...");  
  47.     }  
  48.     return 0;  
  49. }  

client代码

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #include "client.h"  
  2.   
  3. //void cli_hander(int sockfd,)  
  4.   
  5. int main()  
  6. {  
  7.     int sockfd;  
  8.     int rc;   
  9.     int cpid;  
  10.     struct sockaddr_in servaddr;  
  11.       
  12.     bzero(&servaddr,sizeof(servaddr));  
  13.     servaddr.sin_family = AF_INET;  
  14.     inet_pton(AF_INET,"127.0.0.1",&servaddr.sin_addr);  
  15.     servaddr.sin_port = htons(2989);  
  16.       
  17.     for(int i=0;i<20;i++)  
  18.     {     
  19.         cpid = fork();  
  20.         if(cpid == 0)  
  21.         {     
  22.             sockfd = socket(AF_INET,SOCK_STREAM,0);  
  23.             rc = connect(sockfd,(struct sockaddr*)&servaddr,sizeof(servaddr));  
  24.             if(rc == -1)   
  25.             {     
  26.                 perror("connect error");  
  27.                 exit(0);  
  28.             }     
  29.             printf("pid#%d connected...\n",getpid());  
  30.             sleep(3);  
  31.             close(sockfd);  
  32.             exit(0);  
  33.         }     
  34.     }     
  35.   
  36.     while(1)  
  37.     {     
  38.         cpid = wait(NULL);  
  39.         if(cpid==-1){  
  40.             perror("end of wait");  
  41.             break;  
  42.         }  
  43.         printf("pid#%d exit...\n",cpid);  
  44.     }  
  45.     return 0;  
  46. }  

实验结果:

服务器端显示:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. root@cloud2:~/slp/NetWrokProgram/server# ./aworker 2  
  2. new connection...  
  3. new connection...  
  4. new connection...  
  5. new connection...  
  6. new connection...  

客户端显示:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. root@cloud2:~/slp/NetWrokProgram/client# ./a.out   
  2. pid#16697 connected...  
  3. pid#16699 connected...  
  4. pid#16698 connected...  
  5. pid#16697 exit...  
  6. pid#16699 exit...  
  7. pid#16698 exit...  
  8. pid#16700 connected...  
  9. pid#16701 connected...  
  10. pid#16700 exit...  
  11. pid#16701 exit...  
  12. connect error: Connection timed out  
  13. connect error: Connection timed out  
  14. connect error: Connection timed out  
  15. connect error: Connection timed out  
  16. connect error: Connection timed out  
  17. connect error: Connection timed out  
  18. connect error: Connection timed out  
  19. connect error: Connection timed out  
  20. connect error: Connection timed out  
  21. connect error: Connection timed out  
  22. connect error: Connection timed out  
  23. connect error: Connection timed out  
  24. connect error: Connection timed out  
  25. connect error: Connection timed out  
  26. connect error: Connection timed out  
  27. pid#16702 exit...  
  28. pid#16703 exit...  
  29. pid#16704 exit...  
  30. pid#16705 exit...  
  31. pid#16706 exit...  
  32. pid#16707 exit...  
  33. pid#16708 exit...  
  34. pid#16709 exit...  
  35. pid#16710 exit...  
  36. pid#16711 exit...  
  37. pid#16712 exit...  
  38. pid#16713 exit...  
  39. pid#16714 exit...  
  40. pid#16715 exit...  
  41. pid#16716 exit...  
  42. end of wait: No child processes  

结果分析:

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

实例分析2

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

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ...  
  2. listen(listenfd,queuelen);  
  3. sleep(60); //将这个注释,会出现另一种情况哟~~    
  4. while(1)  
  5. {  
  6.     connfd = accept(listenfd,NULL,0);  
  7.     ....  

同样的运行,结果如下:

[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. root@cloud2:~/slp/NetWrokProgram/server# ./aworker 2  
  2. new connection...  
  3. new connection...  
  4. new connection...  
  5. new connection...  
  6. new connection...  
  7. new connection...  
  8. new connection...  
  9. new connection...  
  10. new connection...  
  11. new connection...  
  12. new connection...  
  13. new connection...  
  14. new connection...  
  15. new connection...  
  16. new connection...  
  17. new connection...  
  18. new connection...  
  19. new connection...  
  20. new connection...  
  21. new connection...  

客户端:
[html]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. root@cloud2:~/slp/NetWrokProgram/client# ./a.out   
  2. pid#16736 connected...  
  3. pid#16737 connected...  
  4. pid#16738 connected...  
  5. pid#16739 connected...  
  6. pid#16740 connected...  
  7. pid#16741 connected...  
  8. pid#16742 connected...  
  9. pid#16743 connected...  
  10. pid#16744 connected...  
  11. pid#16745 connected...  
  12. pid#16746 connected...  
  13. pid#16747 connected...  
  14. pid#16748 connected...  
  15. pid#16749 connected...  
  16. pid#16750 connected...  
  17. pid#16751 connected...  
  18. pid#16752 connected...  
  19. pid#16753 connected...  
  20. pid#16755 connected...  
  21. pid#16754 connected...  
  22. pid#16736 exit...  
  23. pid#16737 exit...  
  24. pid#16738 exit...  
  25. pid#16739 exit...  
  26. pid#16740 exit...  
  27. pid#16741 exit...  
  28. pid#16742 exit...  
  29. pid#16743 exit...  
  30. pid#16744 exit...  
  31. pid#16745 exit...  
  32. pid#16746 exit...  
  33. pid#16747 exit...  
  34. pid#16748 exit...  
  35. pid#16749 exit...  
  36. pid#16750 exit...  
  37. pid#16751 exit...  
  38. pid#16752 exit...  
  39. pid#16753 exit...  
  40. pid#16755 exit...  
  41. pid#16754 exit...  
  42. end of wait: No child processes  

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

原文链接:
http://blog.csdn.net/ordeder/article/details/2155156
7
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值