生活随笔
收集整理的這篇文章主要介紹了
实例说明listen()函数第二个参数的意义与用法
小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
我們先來(lái)看結(jié)果:
Client:
[cpp] view plain
copy #include?<sys/socket.h>??#include?<stdio.h>??#include?<string.h>??#include?<netinet/in.h>??#include?<stdlib.h>??#include?<arpa/inet.h>????int?main(int?argc,char**?argv)??{??????int?ret;??????int?sockfd?=?socket(AF_INET,SOCK_STREAM,0);??????if?(sockfd?==?-1)??????{??????????printf("socket?error\n");??????????return?-1;??????}????????struct?sockaddr_in?serveraddr;??????memset(&serveraddr,0,sizeof(serveraddr));??????serveraddr.sin_family?=?AF_INET;??????inet_aton(argv[1],&serveraddr.sin_addr);??????serveraddr.sin_port?=?htons((unsigned?short)(atoi(argv[2])));????????????ret?=?connect(sockfd,(const?sockaddr*)&serveraddr,sizeof(serveraddr));??????if?(ret?==?-1)??????{??????????printf("connect?error,ret?=?%d\n",ret);??????????return?-1;??????}??????????for(;;)??????{}??????return?0;??}??
Server:
[cpp] view plain
copy #include?<sys/socket.h>??#include?<stdio.h>??#include?<string.h>??#include?<netinet/in.h>??#include?<stdlib.h>??#include?<arpa/inet.h>??????int?main(int?argc,char**?argv)??{??????int?ret;??????int?listenfd?=?socket(AF_INET,SOCK_STREAM,0);??????if?(listenfd?==?-1)??????{??????????printf("socket?error\n");??????????return?-1;??????}????????struct?sockaddr_in?serveraddr;??????memset(&serveraddr,0,sizeof(serveraddr));??????serveraddr.sin_family?=?AF_INET;??????serveraddr.sin_addr.s_addr?=?htonl(INADDR_ANY);??????serveraddr.sin_port?=?htons((unsigned?short)(atoi(argv[1])));????????ret?=?bind(listenfd,(const?sockaddr*)&serveraddr,sizeof(serveraddr));??????if?(ret?==?-1)??????{??????????printf("bind?error,ret?=?%d\n",ret);??????????return?-1;??????}??????<span?style="WHITE-SPACE:?pre">?</span>int?backlog?=?atoi(argv[2]);??????ret?=?listen(listenfd,?backlog);??????printf("backlog?=?%d,ret?=%d\n",backlog,ret);??????if?(ret?==?-1)??????{??????????printf("listen?error,ret?=?%d\n",ret);??????????return?-1;??????}????????????for(;;)??????{}??????return?0;??}??
server的代碼中通過(guò)命令行的方式傳入backlog的值,以便于我們通過(guò)修改backlog來(lái)觀察不同的backlog對(duì)程序的影響.
開(kāi)啟一個(gè)server與3個(gè)client.
backlog = 1時(shí):
backlog = 2時(shí):
觀察上圖,server在19890端口監(jiān)聽(tīng),3個(gè)client發(fā)起TCP連接。在第一幅圖中,對(duì)client而言,3個(gè)狀態(tài)均為established.對(duì)server而言,2個(gè)連接狀態(tài)為established,一個(gè)為syn_recv.第二幅圖中,對(duì)server而言,3個(gè)鏈接的狀態(tài)均為established。
我們先來(lái)看一下TCP連接的狀態(tài)轉(zhuǎn)換
再說(shuō)回listen(int fd,int backlog)函數(shù),內(nèi)核會(huì)為一個(gè)監(jiān)聽(tīng)套接字維護(hù)兩個(gè)隊(duì)列,當(dāng)有TCP請(qǐng)求到來(lái)時(shí),即3次握手中的syn分節(jié)發(fā)送來(lái)時(shí),會(huì)在未完成隊(duì)列中增加一項(xiàng),3次握手完成時(shí),未完成隊(duì)列中的項(xiàng)就移動(dòng)到已完成隊(duì)列里,accept()函數(shù)會(huì)從已連接隊(duì)列里取走已完成連接.
這個(gè)backlog參數(shù)就是控制我們的已連接隊(duì)列里等待accept()取走的連接的最大數(shù)目的.注意一點(diǎn),backlog與這個(gè)已排隊(duì)連接的最大數(shù)目未必是完全相等的,不同的系統(tǒng)的實(shí)現(xiàn)可能不同.比如backlog=1,系統(tǒng)允許的實(shí)際一排隊(duì)數(shù)目可能為2.
所以在上圖中,對(duì)client而言,connect()返回,TCP的狀態(tài)就轉(zhuǎn)變?yōu)閑stablished。而對(duì)server而言,3次握手完成TCP狀態(tài)才會(huì)轉(zhuǎn)換為established。在圖一中,由于backlog參數(shù)的限制,導(dǎo)致有一條連接并未完成3次握手,所以狀態(tài)為syn_recv。
總結(jié)
以上是生活随笔為你收集整理的实例说明listen()函数第二个参数的意义与用法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。