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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

close和SO_LINGER

發布時間:2025/6/15 编程问答 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 close和SO_LINGER 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

? ? ? ? ? ? ? close函數的作用是關閉套接字,并終止TCP連接。unix網絡編程這本書上是這樣說的,我覺得這個解釋有人會讓人產生誤解。close了某個socket,該socket就真的必須關閉嗎?其實不是,close是將該套接字的引用計數減1,當某個套接字的引用計數為0時,該套接字就被關閉了;不為0,就不會被關閉。多進程并發服務器中會出現這種情況,我開始就誤解了。

? ? ? ? ? ? ? SO_LINGER套接字選項是用來設置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]$

?

編譯并運行,客戶端需要打開另一個窗口執行。

?

[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

?

運行客戶端,并查看網絡狀態。

?

[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立即返回了,套接字關閉了,但客戶端發送緩沖區中仍然還有數據。當服務端接收緩沖區有地方后,這些數據將會由系統自動發送給服務端,但是此時客戶端講不會管服務端是否已接收到數據。l_onoff=0,就是關閉這個套接字選項,默認close操作。注意觀察,此時客戶端的狀態時FIN_WAIT1,就是客戶單還沒有把數據發送完畢,所以沒有接到服務端協議棧返回的ACK,所以客戶端為這個狀態。

?

再改變客戶端代碼:

?

#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; }


還是按照上述操作,編譯后啟動服務端和客戶端。此時會發現客戶端卡在getchar()處,查看此時的網絡狀態。

?

?

[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 ~]$

?

?

?

客戶端的發送緩沖區中還沒有數據發送出去,如果是我們說的第一種情況,在客戶端按下回車鍵之后,客戶端應該FIN_WAIT1狀態。好,我們在客戶端按下回車鍵后看網絡狀態。

?

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

?

?

看,連接直接斷開了。說明close調用后,會丟棄發送緩沖區的內存,并發送一個RST給服務端,從而斷開連接,這也避免了time_wait的狀態。這也是將?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; }


還是重復上述操作,編譯運行查看網絡狀態,此時我將getchar()注釋掉了。你會看到客戶端會卡在那里,其原因是調用了close函數,但是它不會馬上返回,close等待的時間是我們設置的超時時間??创藭r的網絡狀態。

?

?

[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 ~]$

?

?

?

當客戶端發送緩沖區中的數據全部發送到服務端的協議棧,并且接收到了服務端的ACK,那么此時close就會返回,前提是在我們設置的超時時間之內。過了超時時間,close也會返回,那就和我們說的第一種情況一樣了。

網絡問題本應該用tcpdump抓包來看效果的,但是很遺憾,我正在測試的linux上沒有root權限。

?

?

參考資料:unix網絡編程卷一

?


?

?

?

?

?

?

?

?

?

總結

以上是生活随笔為你收集整理的close和SO_LINGER的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。