生活随笔
收集整理的這篇文章主要介紹了
listen()函数中backlog参数分析
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
背景知識
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個客戶端與服務器建立連接,查看連接的建立情況。
服務器代碼:
[cpp] view plain
copy #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代碼
[cpp] view plain
copy #include?"client.h"????????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;??}??
實驗結果:
服務器端顯示:
[cpp] view plain
copy root@cloud2:~/slp/NetWrokProgram/server#?./aworker?2??new?connection...??new?connection...??new?connection...??new?connection...??new?connection...??
客戶端顯示:
[cpp] view plain
copy 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?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??connect?error:?Connection?timed?out??pid#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阻塞:
[html] view plain
copy ...??listen(listenfd,queuelen);??sleep(60);?//將這個注釋,會出現另一種情況喲~~????while(1)??{??????connfd?=?accept(listenfd,NULL,0);??????....?? 同樣的運行,結果如下:
[html] view plain
copy root@cloud2:~/slp/NetWrokProgram/server#?./aworker?2??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...??new?connection...?? 客戶端:
[html] view plain
copy 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
總結
以上是生活随笔為你收集整理的listen()函数中backlog参数分析的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。