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個客戶端與伺服器建立連線,檢視連線的建立情況。
伺服器程式碼:
- #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
- 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;
- }
實驗結果:
伺服器端顯示:
- [email protected]:~/slp/NetWrokProgram/server# ./aworker 2
- new connection...
- new connection...
- new connection...
- new connection...
- new connection...
客戶端顯示:
- [email protected]:~/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阻塞:- ...
- listen(listenfd,queuelen);
- sleep(60); //將這個註釋,會出現另一種情況喲~~
- while(1)
- {
- connfd = accept(listenfd,NULL,0);
- ....
同樣的執行,結果如下:
- [email protected]:~/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...
客戶端:
- [email protected]:~/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...
-
相關推薦
isten()函式中backlog引數分析
背景知識 Unix網路程式設計描述如下: 總結 0. accept()函式不參與三次握手,而只負責從已建立連線佇列中取出一個連線和sockfd進行繫結; 1. backlog引數決定了未完成佇列和已完成佇列中連線數目之和的最大值(從核心角度看,是否這個和就是
Linux中listen()系統呼叫的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] '''  
函式中的引數為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) ''' 講道理來說輸出