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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

socket 编程的端口和地址复用

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

在linux socket網絡編程中,大規模并發TCP或UDP連接時,經常會用到端口復用:

int opt = 1;if(setsockopt(sockfd, SOL_SOCKET,SO_REUSEADDR, (const void *) &opt, sizeof(opt))){perror("setsockopt");return -1; }

那么什么是端口復用呢,如何理解呢,可以解釋成如下:?
在A機上進行客戶端網絡編程,假如它所使用的本地端口號是1234,如果沒有開啟端口復用的話,它用本地端口1234去連接B機再用本地端口連接C機時就不可以,若開啟端口復用的話在用本地端口1234訪問B機的情況下還可以用本地端口1234訪問C機。若是服務器程序中監聽的端口,即使開啟了復用,也不可以用該端口望外發起連接了。

SO_REUSEADDR和SO_REUSEPORT

SO_REUSEADDR提供如下四個功能:

SO_REUSEADDR允許啟動一個監聽服務器并捆綁其眾所周知端口,即使以前建立的將此端口用做他們的本地端口的連接仍存在。這通常是重啟監聽服務器時出現,若不設置此選項,則bind時將出錯。SO_REUSEADDR允許在同一端口上啟動同一服務器的多個實例,只要每個實例捆綁一個不同的本地IP地址即可。對于TCP,我們根本不可能啟動捆綁相同IP地址和相同端口號的多個服務器。SO_REUSEADDR允許單個進程捆綁同一端口到多個套接口上,只要每個捆綁指定不同的本地IP地址即可。這一般不用于TCP服務器。SO_REUSEADDR允許完全重復的捆綁:當一個IP地址和端口綁定到某個套接口上時,還允許此IP地址和端口捆綁到另一個套接口上。一般來說,這個特性僅在支持多播的系統上才有,而且只對UDP套接口而言(TCP不支持多播)。

SO_REUSEPORT選項有如下語義:

此選項允許完全重復捆綁,但僅在想捆綁相同IP地址和端口的套接口都指定了此套接口選項才行。如果被捆綁的IP地址是一個多播地址,則SO_REUSEADDR和SO_REUSEPORT等效。

使用這兩個套接口選項的建議:

在所有TCP服務器中,在調用bind之前設置SO_REUSEADDR套接口選項;

當編寫一個同一時刻在同一主機上可運行多次的多播應用程序時,設置SO_REUSEADDR選項,并將本組的多播地址作為本地IP地址捆綁。

setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (const void *)&nOptval , sizeof(int)) < 0)?

Q:編寫 TCP/SOCK_STREAM 服務程序時,SO_REUSEADDR到底什么意思?A:這個套接字選項通知內核,如果端口忙,但TCP狀態位于 TIME_WAIT ,可以重用端口。如果端口忙, 而TCP狀態位于其他狀態,重用端口時依舊得到一個錯誤信息,指明"地址已經使用中"。如果你的服務程序停止 后想立即重啟,而新套接字依舊使用同一端口,此時SO_REUSEADDR 選項非常有用。必須意識到,此時任何 非期望數據到達,都可能導致服務程序反應混亂,不過這只是一種可能,事實上很不可能。 其實這個問題在Richard Stevens的《Unix網絡編程指南》卷一里有很詳細的解答(中文版P166-168頁)。這里我只是寫幾個基本的例子來驗證這個問題。
首先聲明一個問題: 當兩個socket的address和port相沖突,而你又想重用地址和端口,則舊的socket和新的socket都要已經被設置了SO_REUSEADDR特性,只有兩者之一有這個特性還是有問題的。
SO_REUSEADDR可以用在以下四種情況下。
(摘自《Unix網絡編程》卷一,即UNPv1)
1、當有一個有相同本地地址和端口的socket1處于TIME_WAIT狀態時,而你啟動的程序的socket2要占用該地址和端口,你的程序就要用到該選項。
2、SO_REUSEADDR允許同一port上啟動同一服務器的多個實例(多個進程)。但每個實例綁定的IP地址是不能相同的。在有多塊網卡或用IP Alias技術的機器可以測試這種情況。
3、SO_REUSEADDR允許單個進程綁定相同的端口到多個socket上,但每個socket綁定的ip地址不同。這和2很相似,區別請看UNPv1。

4、SO_REUSEADDR允許完全相同的地址和端口的重復綁定。但這只用于UDP的多播,不用于TCP。

源碼:

[cpp]?view plain?copy
  • #include?<stdio.h>??
  • #include?<stdlib.h>??
  • ??
  • #include?<sys/socket.h>????
  • #include?<netinet/in.h>????
  • #include?<arpa/inet.h>????
  • #include?<sys/types.h>????
  • #include?<unistd.h>????
  • ??
  • #define?MAXLINE?100??
  • ??
  • int?main(int?argc,?char**?argv)??
  • {??
  • ????int?listenfd,connfd;??
  • ????struct?sockaddr_in?servaddr;??
  • ????char?buff[MAXLINE+1];??
  • ????time_t?ticks;??
  • ????unsigned?short?port;??
  • ????int?flag=1,len=sizeof(int);??
  • ??
  • ????port=10013;??
  • ????if(?(listenfd=socket(AF_INET,SOCK_STREAM,0))?==?-1)??
  • ????{??
  • ????????perror("socket");??
  • ????????exit(1);??
  • ????}??
  • ????bzero(&servaddr,sizeof(servaddr));??
  • ????servaddr.sin_family=AF_INET;??
  • ????servaddr.sin_addr.s_addr=htonl(INADDR_ANY);??
  • ????servaddr.sin_port=htons(port);??
  • ????/**/if(?setsockopt(listenfd,?SOL_SOCKET,?SO_REUSEADDR,?&flag,?len)?==?-1)??
  • ????{??
  • ????????perror("setsockopt");??
  • ????????exit(1);??
  • ????}??
  • ????if(?bind(listenfd,(struct?sockaddr*)&servaddr,sizeof(servaddr))?==-1)??
  • ????{??
  • ????????perror("bind");??
  • ????????exit(1);??
  • ????}??
  • ????else??
  • ????????printf("bind?call?OK!\n");??
  • ????if(?listen(listenfd,5)?==?-1)??
  • ????{??
  • ????????perror("listen");??
  • ????????exit(1);??
  • ????}??
  • ??
  • ????for(;;)?{??
  • ????????if(?(connfd=accept(listenfd,(struct?sockaddr*)NULL,NULL))?==?-1)??
  • ????????{??
  • ????????????perror("accept");??
  • ????????????exit(1);??
  • ????????}??
  • ????????if(?fork()?==?0)/**//*child?process*/??
  • ????????{??
  • ????????????close(listenfd);/**//*這句不能少,原因請大家想想就知道了。*/??
  • ????????????ticks=time(NULL);??
  • ????????????snprintf(buff,100,"%.24s\r\n",ctime(&ticks));??
  • ????????????write(connfd,buff,strlen(buff));??
  • ????????????close(connfd);??
  • ????????????sleep(1);??
  • ????????????execlp("f1-9d",NULL);??
  • ????????????perror("execlp");??
  • ????????????exit(1);??
  • ????????}??
  • ????????close(connfd);??
  • ????????exit(0);/**//*?end?parent*/??
  • ????}??
  • } ?
  • 總結

    以上是生活随笔為你收集整理的socket 编程的端口和地址复用的全部內容,希望文章能夠幫你解決所遇到的問題。

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