listen函数
? ? ? ? ? listen函數(shù),從英語上理解就是一個"聽"函數(shù),實(shí)際上它也就是這個意思。我們來看unix網(wǎng)絡(luò)編程這本書是怎樣對它的解釋:listen函數(shù)把一個未連接的套接字轉(zhuǎn)換成一個被動套接字,指示內(nèi)核應(yīng)該接受指向該套接字的鏈接請求。該函數(shù)有2個參數(shù),第一個我就不說了,第二參數(shù)規(guī)定了內(nèi)核為相應(yīng)套接字排隊(duì)的最大連接個數(shù)。只看這些理論搞的人稀里糊涂,我們還是來測一下。
?
[mapan@localhost test]$ ls client.cpp makefile server.cpp [mapan@localhost test]$ [mapan@localhost test]$ cat server.cpp #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <malloc.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <stdarg.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #define MAXLINE 4096void main() {int listenfd,connfd;socklen_t clilen;struct sockaddr_in cliaddr,servaddr;listenfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_addr.s_addr=INADDR_ANY;servaddr.sin_port=htons(8888);bind(listenfd,(struct sockaddr *)&servaddr,sizeof(servaddr)); listen(listenfd,1);getchar();connfd=accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);close(connfd);close(listenfd); } [mapan@localhost test]$ cat client.cpp #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include <netdb.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <errno.h> #include <malloc.h> #include <netinet/in.h> #include <arpa/inet.h> #include <sys/ioctl.h> #include <stdarg.h> #include <fcntl.h> #include <sys/types.h> #include <sys/wait.h> #include <netinet/in.h> #include <arpa/inet.h> #include <signal.h> #define MAXLINE 4096void main() {int sockfd;struct sockaddr_in servaddr;sockfd=socket(AF_INET,SOCK_STREAM,0);bzero(&servaddr,sizeof(servaddr));servaddr.sin_family=AF_INET;servaddr.sin_port=htons(8888);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));getchar();close(sockfd); } [mapan@localhost test]$ cat makefile all:server clientserver.o:server.cppg++ -c server.cpp client.o:client.cppg++ -c client.cpp server:server.og++ -o server server.o client:client.og++ -o client client.oclean:rm -f server client *.o [mapan@localhost test]$?
?
請注意上面的服務(wù)端中,我是沒有調(diào)用accept函數(shù)的,直接調(diào)用getchar()了,跑起來。
?
[mapan@localhost test]$ make g++ -c server.cpp g++ -o server server.o g++ -c client.cpp g++ -o client client.o [mapan@localhost test]$ ./server服務(wù)度開啟,然后新打開一個窗口開啟客戶端。
[mapan@localhost TCP]$ cd ../test/ [mapan@localhost test]$ [mapan@localhost test]$ ./client 127.0.0.1?
查看網(wǎng)絡(luò):
[mapan@localhost test]$ netstat -na | grep 8888 tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:34846 127.0.0.1:8888 ESTABLISHED tcp 0 0 127.0.0.1:8888 127.0.0.1:34846 ESTABLISHED [mapan@localhost test]$看,已經(jīng)建立起一個連接了。但是我們沒有調(diào)用accept函數(shù),連接還是建立起來了,這說說明accept函數(shù)和TCP三次握手沒啥關(guān)系,這也是一個知識盲點(diǎn)。好,在開啟一個新窗口運(yùn)行客戶端,查看網(wǎng)絡(luò)狀態(tài)。(新開窗口運(yùn)行客戶端同上,這里就不用代碼演示了)
?
?
[mapan@localhost test]$ netstat -na | grep 8888 tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:34846 127.0.0.1:8888 ESTABLISHED tcp 0 0 127.0.0.1:34848 127.0.0.1:8888 ESTABLISHED tcp 0 0 127.0.0.1:8888 127.0.0.1:34846 ESTABLISHED tcp 0 0 127.0.0.1:8888 127.0.0.1:34848 ESTABLISHED
看,又建立起一個連接。在運(yùn)行一個客戶端,看網(wǎng)絡(luò)狀態(tài)。
?
[mapan@localhost test]$ netstat -na | grep 8888 tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:8888 127.0.0.1:34850 SYN_RECV tcp 0 0 127.0.0.1:34846 127.0.0.1:8888 ESTABLISHED tcp 0 0 127.0.0.1:34848 127.0.0.1:8888 ESTABLISHED tcp 0 0 127.0.0.1:8888 127.0.0.1:34846 ESTABLISHED tcp 0 0 127.0.0.1:8888 127.0.0.1:34848 ESTABLISHED tcp 0 0 127.0.0.1:34850 127.0.0.1:8888 ESTABLISHED
當(dāng)?shù)谌齻€客戶端連接進(jìn)來的時候,出現(xiàn)了一個SYN_RECV,這標(biāo)明第三個客戶端沒有與服務(wù)端建立連接。我們listen函數(shù)設(shè)置的監(jiān)聽隊(duì)列為1,那么監(jiān)聽隊(duì)列塞了2個之后就沒有往里面塞了。這下大概懂了listen函數(shù)第二個參數(shù)的意義了吧,當(dāng)參數(shù)為1的時候只能監(jiān)聽2個套接字,這應(yīng)該是從0開始數(shù)的。為什么是大概呢?其實(shí)unix網(wǎng)絡(luò)編程上是這樣說的:listen函數(shù)的第二個參數(shù)是ESTABLISHED和SYN_RECV之和,只是在監(jiān)聽隊(duì)列沒有滿的情況下,SYN_RECV狀態(tài)不容易重現(xiàn)。這時候在服務(wù)度輸入一個字符會有啥效果呢?答案告訴你,就是那個SYN_RECV狀態(tài)變成ESTABLISHED了,這也是 accept函數(shù)的作用。accept函數(shù)會將已完成連接隊(duì)列中的對頭項(xiàng)返回給進(jìn)程,所以SYN_RECV變成ESTABLISHED了。這個現(xiàn)象留給大家去實(shí)踐一下吧,只有自己實(shí)踐出來的東西才是自己的。
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
?
《新程序員》:云原生和全面數(shù)字化實(shí)踐50位技術(shù)專家共同創(chuàng)作,文字、視頻、音頻交互閱讀總結(jié)
- 上一篇: bind函数
- 下一篇: shutdown函数和FIN_WAIT2