日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

close和SO_LINGER

發(fā)布時(shí)間:2025/6/15 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 close和SO_LINGER 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

? ? ? ? ? ? ? close函數(shù)的作用是關(guān)閉套接字,并終止TCP連接。unix網(wǎng)絡(luò)編程這本書(shū)上是這樣說(shuō)的,我覺(jué)得這個(gè)解釋有人會(huì)讓人產(chǎn)生誤解。close了某個(gè)socket,該socket就真的必須關(guān)閉嗎?其實(shí)不是,close是將該套接字的引用計(jì)數(shù)減1,當(dāng)某個(gè)套接字的引用計(jì)數(shù)為0時(shí),該套接字就被關(guān)閉了;不為0,就不會(huì)被關(guān)閉。多進(jìn)程并發(fā)服務(wù)器中會(huì)出現(xiàn)這種情況,我開(kāi)始就誤解了。

? ? ? ? ? ? ? SO_LINGER套接字選項(xiàng)是用來(lái)設(shè)置close操作的。直接看代碼吧。

?

[mapan@localhost test]$ ls client.cpp makefile server.cpp [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 4096int main() {int listenfd,acceptfd;socklen_t clilen;struct sockaddr_in cliaddr,servaddr;listenfd=socket(AF_INET,SOCK_STREAM,0);servaddr.sin_family=AF_INET;servaddr.sin_port=htons(8888);servaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); bind(listenfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr_in));listen(listenfd,5);acceptfd=accept(listenfd,(struct sockaddr *)NULL,NULL);char recvbuf[200000];while(1){getchar();read(acceptfd,recvbuf,sizeof(recvbuf)); }getchar();close(listenfd);return 0; } [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 4096int 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");struct linger so_linger;so_linger.l_onoff=0;//so_linger.l_linger=20;setsockopt(sockfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger)); int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));char sendbuf[200000];write(sockfd,sendbuf,sizeof(sendbuf)); close(sockfd);return 0; }[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]$

?

編譯并運(yùn)行,客戶端需要打開(kāi)另一個(gè)窗口執(zhí)行。

?

[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

?

運(yùn)行客戶端,并查看網(wǎng)絡(luò)狀態(tài)。

?

[mapan@localhost test]$ ./client [mapan@localhost test]$ [mapan@localhost ~]$ netstat -na | grep 8888 tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN tcp 0 61101 127.0.0.1:35260 127.0.0.1:8888 FIN_WAIT1 tcp 138900 0 127.0.0.1:8888 127.0.0.1:35260 ESTABLISHED [mapan@localhost ~]$

?

?

可以看到的是close立即返回了,套接字關(guān)閉了,但客戶端發(fā)送緩沖區(qū)中仍然還有數(shù)據(jù)。當(dāng)服務(wù)端接收緩沖區(qū)有地方后,這些數(shù)據(jù)將會(huì)由系統(tǒng)自動(dòng)發(fā)送給服務(wù)端,但是此時(shí)客戶端講不會(huì)管服務(wù)端是否已接收到數(shù)據(jù)。l_onoff=0,就是關(guān)閉這個(gè)套接字選項(xiàng),默認(rèn)close操作。注意觀察,此時(shí)客戶端的狀態(tài)時(shí)FIN_WAIT1,就是客戶單還沒(méi)有把數(shù)據(jù)發(fā)送完畢,所以沒(méi)有接到服務(wù)端協(xié)議棧返回的ACK,所以客戶端為這個(gè)狀態(tài)。

?

再改變客戶端代碼:

?

#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 4096int 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");struct linger so_linger;so_linger.l_onoff=1;so_linger.l_linger=0;setsockopt(sockfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger)); int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));char sendbuf[200000];write(sockfd,sendbuf,sizeof(sendbuf)); getchar();close(sockfd);return 0; }


還是按照上述操作,編譯后啟動(dòng)服務(wù)端和客戶端。此時(shí)會(huì)發(fā)現(xiàn)客戶端卡在getchar()處,查看此時(shí)的網(wǎng)絡(luò)狀態(tài)。

?

?

[mapan@localhost ~]$ netstat -na | grep 8888 tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN tcp 138900 0 127.0.0.1:8888 127.0.0.1:35262 ESTABLISHED tcp 0 61100 127.0.0.1:35262 127.0.0.1:8888 ESTABLISHED [mapan@localhost ~]$

?

?

?

客戶端的發(fā)送緩沖區(qū)中還沒(méi)有數(shù)據(jù)發(fā)送出去,如果是我們說(shuō)的第一種情況,在客戶端按下回車鍵之后,客戶端應(yīng)該FIN_WAIT1狀態(tài)。好,我們?cè)诳蛻舳税聪禄剀囨I后看網(wǎng)絡(luò)狀態(tài)。

?

[mapan@localhost ~]$ netstat -na | grep 8888 tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN [mapan@localhost ~]$

?

?

看,連接直接斷開(kāi)了。說(shuō)明close調(diào)用后,會(huì)丟棄發(fā)送緩沖區(qū)的內(nèi)存,并發(fā)送一個(gè)RST給服務(wù)端,從而斷開(kāi)連接,這也避免了time_wait的狀態(tài)。這也是將?so_linger.l_onoff=1,so_linger.l_linger=0的close效果。

?

在看客戶端代碼:

?

[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 4096int 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");struct linger so_linger;so_linger.l_onoff=1;so_linger.l_linger=10;setsockopt(sockfd,SOL_SOCKET,SO_LINGER,&so_linger,sizeof(so_linger)); int ret=connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));char sendbuf[200000];write(sockfd,sendbuf,sizeof(sendbuf)); //getchar();close(sockfd);return 0; }


還是重復(fù)上述操作,編譯運(yùn)行查看網(wǎng)絡(luò)狀態(tài),此時(shí)我將getchar()注釋掉了。你會(huì)看到客戶端會(huì)卡在那里,其原因是調(diào)用了close函數(shù),但是它不會(huì)馬上返回,close等待的時(shí)間是我們?cè)O(shè)置的超時(shí)時(shí)間。看此時(shí)的網(wǎng)絡(luò)狀態(tài)。

?

?

[mapan@localhost ~]$ netstat -na | grep 8888 tcp 0 0 127.0.0.1:8888 0.0.0.0:* LISTEN tcp 0 61101 127.0.0.1:35266 127.0.0.1:8888 FIN_WAIT1 tcp 138900 0 127.0.0.1:8888 127.0.0.1:35266 ESTABLISHED [mapan@localhost ~]$

?

?

?

當(dāng)客戶端發(fā)送緩沖區(qū)中的數(shù)據(jù)全部發(fā)送到服務(wù)端的協(xié)議棧,并且接收到了服務(wù)端的ACK,那么此時(shí)close就會(huì)返回,前提是在我們?cè)O(shè)置的超時(shí)時(shí)間之內(nèi)。過(guò)了超時(shí)時(shí)間,close也會(huì)返回,那就和我們說(shuō)的第一種情況一樣了。

網(wǎng)絡(luò)問(wèn)題本應(yīng)該用tcpdump抓包來(lái)看效果的,但是很遺憾,我正在測(cè)試的linux上沒(méi)有root權(quán)限。

?

?

參考資料:unix網(wǎng)絡(luò)編程卷一

?


?

?

?

?

?

?

?

?

?

總結(jié)

以上是生活随笔為你收集整理的close和SO_LINGER的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。