1. 程式人生 > >isten()函式中backlog引數分析

isten()函式中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個客戶端與伺服器建立連線,檢視連線的建立情況。

伺服器程式碼:

  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. int main(int argc,char*argv[])  
  14. {  
  15.     int listenfd,connfd;  
  16.     struct
     sockaddr_in cliaddr,servaddr;  
  17.     int queuelen=5;  
  18.     if(argc!=2){  
  19.         puts("usage# ./aworker listenqueuelen");  
  20.         exit(0);  
  21.     }     
  22.     queuelen=atoi(argv[1]);  
  23.     listenfd = socket(AF_INET,SOCK_STREAM,0);  
  24.     bzero(&servaddr,sizeof(servaddr));  
  25.     servaddr.sin_family = AF_INET;  
  26.     servaddr.sin_addr.s_addr = htonl(INADDR_ANY);  
  27.     servaddr.sin_port = htons(2989);  
  28.     bind(listenfd,(struct sockaddr*)&servaddr,sizeof(servaddr));  
  29.     listen(listenfd,queuelen);  
  30.     sleep(60); //將這個註釋,會出現另一種情況喲~~  
  31.     while(1)  
  32.     {  
  33.         connfd = accept(listenfd,NULL,0);  
  34.         if(connfd == -1)  
  35.         {  
  36.             perror("accept error");  
  37.             continue;  
  38.         }  
  39.         puts("new connection...");  
  40.     }  
  41.     return 0;  
  42. }  

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

實驗結果:

伺服器端顯示:

  1. [email protected]:~/slp/NetWrokProgram/server# ./aworker 2  
  2. new connection...  
  3. new connection...  
  4. new connection...  
  5. new connection...  
  6. new connection...  

客戶端顯示:
  1. [email protected]:~/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阻塞:
  1. ...  
  2. listen(listenfd,queuelen);  
  3. sleep(60); //將這個註釋,會出現另一種情況喲~~    
  4. while(1)  
  5. {  
  6.     connfd = accept(listenfd,NULL,0);  
  7.     ....  

同樣的執行,結果如下:
  1. [email protected]:~/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...  

客戶端:
  1. [email protected]:~/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. 相關推薦

    isten()函式backlog引數分析

    背景知識 Unix網路程式設計描述如下: 總結 0. accept()函式不參與三次握手,而只負責從已建立連線佇列中取出一個連線和sockfd進行繫結; 1. backlog引數決定了未完成佇列和已完成佇列中連線數目之和的最大值(從核心角度看,是否這個和就是

    Linuxlisten()系統呼叫的backlog引數分析

    這篇文章是對上一篇部落格網路程式設計常用介面的核心實現----sys_listen()的補充,上篇文章中我說listen()系統呼叫的backlog引數既是連線佇列的長度,也指定了半連線佇列的長度(不能說等於),而不是《Unix網路程式設計》中講到的是半連線佇列和連線佇列

    [Python筆記]函式關鍵字引數,收集引數與分配引數的使用例項

    Stock類 class Stock: def __init__(self): self.itemList = [] def addItem(self, name, price): # 建立商品 return {'name': name

    getopt----解析main函式引數

       轉自------  Linux下getopt()函式的簡單使用   "a:b:cd::e",這就是一個選項字串。對應到命令列就是-a ,-b ,-c ,-d, -e 。冒號又是什麼呢? 冒號表示引數,一個冒號就表示這個選項後面必須

    不可不知:函式預設引數的陷阱

    現象 def foo(x, y=[]): y.append(x) return y print(foo(1)) print(foo(1, [3, 4])) print(foo(5)) ''' [1] [3, 4, 1] [1, 5] '''       

    Linux Cmain函式引數argc和argv

                                              &

    函式引數為object... 和 object[] 的區別

    先給出兩個示例函式 方法1: public void testobject(object... params){ ///省略此處程式碼 } 方法2: public void testobject(object[] params){ ///省略此處程式碼 }   區別

    Java程式利用main函式args引數實現引數的傳遞

    1.執行Java程式的同時,可以通過輸入引數給main函式中的接收引數陣列args[],供程式內部使用!即當你在Java命令列後面帶上引數,Java虛擬機器就直接把它們存放到了main方法中的引數String數組裡了。 2..args是Java命令列引數,因為引數可以為多個,所以要用陣列來存

    Python 函式引數是傳值,還是傳引用?

    在 C/C++ 中,傳值和傳引用是函式引數傳遞的兩種方式,在Python中引數是如何傳遞的?回答這個問題前,不如先來看兩段程式碼。 程式碼段1: def foo(arg): arg = 2 print(arg) a = 1 foo(a) # 輸出:2 print(a) #

    Kotlin函式預設引數

    Java不支援預設引數。但kotlin函式卻可以 package loaderman.demo class Customer(var name:String ="name"){//預設引數 init { print(name) } } pack

    R語言函式特殊引數"..."

    “...”用來引用從被呼叫函式傳遞下來的引數。當所有匹配“...”的引數來自特定的類或者特定類的子類,  為這些函式定義的方法會被選擇和呼叫。  fun1 <- function(data, data.frame, graph=TRUE, limit=20, ...)

    lua函式引數與返回值與print函式

    function hanshu1() a=2222 print("111111111111") print(a) end function hanshu2(a,b,c,d) print(a,

    關於C#事件處理函式引數(object sender, EventArgs e)

    1、是事件源,表示觸發事件的那個元件    如(button/label/listview...),比如說你單擊button,那麼sender就是button 2、EventArgs是事件引數,它用

    JNI原生函式JNIEnv引數詳解

    JNIEXPORT jstring JNICALL Java_com_example_hellojni_HelloJni_stringFromJNI(JNIEnv *env,jobject thiz) 原生程式碼通過JNIEnv介面指標提供的各種函式來使

    關於Python函式self引數使用介紹

    摘要:類中函式定義需要加self,類外函式定義不需要 程式碼片 class Foo(object): #類中方法加入了self引數 def say_someThing(self,s

    js動態新增html標籤函式引數寫法

    js動態新增html標籤,此html中包含onclick等事件,必然要引用函式,那麼函式中的引數如何寫? 1,function showi(m){ alert(m); } function change(){ var  x=6; document.write('<a

    Quartz—向execute函式傳入引數

    Quartz向execute函式中傳入引數分三步: 第一步:在JobDetail類的getJobDataMap()方法中新增特定引數及其所對應的值 。 jobDetail.getJobData

    驅動ioctl引數分析

    一、ioctl的簡介: 雖然在檔案操作結構體"structfile_operations"中有很多對應的裝置操作函式,但是有些命令是實在找不到對應的操作函式。如CD-ROM的驅動,想要一個彈出光碟機的操作,這種操作並不是所有的字元裝置都需要的,所以檔案操作結構體也不會有對應

    libvlc_media_add_option 函式引數設定

    libvlc_media_add_option   函式中的引數設定 Usage: vlc [options] [stream] ... You can specify multiple streams on the commandline. They will be

    python函式的預設引數為list時出現異常分析

    遇到一個奇怪的現象: '''python def f(x,l=[]): for i in range(x): l.append(i*i) print l f(2) f(3,[3,2,1]) f(3) ''' 講道理來說輸出