linux網絡編程函數——地址復用setsockopt()


1、setsockopt()作用及簡介

socket關閉之后並不會立即收回,而是要經歷一個TIME_WAIT的階段。此時對這個端口進行重新綁定就會出錯。要想立即綁定端口,需要先設置 SO_REUSEADDR.

或者在closesocket的時候,使用setsockopt設置SO_DONTLINGER。才會消除TIME_WAIT時間,用setsockopt()函數即可實現。

#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
       int setsockopt(int sockfd, int level, int optname,
                      const void *optval, socklen_t optlen);

 /* sockfd:標識一個套接口的描述字。
   level:選項定義的層次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。
   optname:需設置的選項。
   optval:指針,指向存放選項值的緩沖區。
   optlen:optval緩沖區長度。
    返回值:  成功返回0,失敗返回 -1.  */

 

2、具體應用

 1 //地址復用
 2 void set_reuseaddr(int sockfd, int optval)
 3 {
 4     int on = (optval != 0) ? 1 : 0;
 5     //int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
 6     /* sockfd:標識一個套接口的描述字。
 7       level:選項定義的層次;支持SOL_SOCKET、IPPROTO_TCP、IPPROTO_IP和IPPROTO_IPV6。
 8       optname:需設置的選項。
 9       optval:指針,指向存放選項值的緩沖區。
10       optlen:optval緩沖區長度。
11         返回值:  成功返回0,失敗返回 -1.  */
12 
13    if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
14         ERR_EXIT("setsockopt SO_REUSEADDR");
15 }
16 
17 //端口復用
18 void set_reuseport(int sockfd, int optval)
19 {
20 #ifdef SO_REUSEPORT
21     int on = (optval != 0) ? 1 : 0;
22     if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on)) < 0)
23         ERR_EXIT("setsockopt SO_REUSEPORT");
24 #else
25     fprintf(stderr, "SO_REUSEPORT is not supported.\n");
26 #endif //SO_REUSEPORT
27 }

 

3、補充

  1. 如果在已經處於 ESTABLISHED狀態下的socket(一般由端口號和標志符區分)調用
      closesocket(一般不會立即關閉而經歷TIME_WAIT的過程)后想繼續重用該socket:
      BOOL bReuseaddr=TRUE;
      setsockopt(s,SOL_SOCKET ,SO_REUSEADDR,(const 
      char*)&amp;bReuseaddr,sizeof(BOOL));

      2. 如果要已經處於連接狀態的soket在調用closesocket后強制關閉,不經歷
      TIME_WAIT的過程:
      BOOL bDontLinger = FALSE; 
      setsockopt(s,SOL_SOCKET,SO_DONTLINGER,(const 
      char*)&amp;bDontLinger,sizeof(BOOL));

      3.在send(),recv()過程中有時由於網絡狀況等原因,發收不能預期進行,而設置收發時限:
      int nNetTimeout=1000;//1秒
      //發送時限
      setsockopt(socket,SOL_S0CKET,SO_SNDTIMEO,(char 
      *)&amp;nNetTimeout,sizeof(int));
      //接收時限
      setsockopt(socket,SOL_S0CKET,SO_RCVTIMEO,(char 
      *)&amp;nNetTimeout,sizeof(int));

      4.在send()的時候,返回的是實際發送出去的字節(同步)或發送到socket緩沖區的字節
      (異步);系統默認的狀態發送和接收一次為8688字節(約為8.5K);在實際的過程中發送數據
      和接收數據量比較大,可以設置socket緩沖區,而避免了send(),recv()不斷的循環收發:
      // 接收緩沖區
      int nRecvBuf=32*1024;//設置為32K
      setsockopt(s,SOL_SOCKET,SO_RCVBUF,(const char*)&amp;nRecvBuf,sizeof(int));
      //發送緩沖區
      int nSendBuf=32*1024;//設置為32K
      setsockopt(s,SOL_SOCKET,SO_SNDBUF,(const char*)&amp;nSendBuf,sizeof(int));

      5. 如果在發送數據的時,希望不經歷由系統緩沖區到socket緩沖區的拷貝而影響
      程序的性能:
      int nZero=0;
      setsockopt(socket,SOL_S0CKET,SO_SNDBUF,(char *)&amp;nZero,sizeof(nZero));

      6.同上在recv()完成上述功能(默認情況是將socket緩沖區的內容拷貝到系統緩沖區):
      int nZero=0;
      setsockopt(socket,SOL_S0CKET,SO_RCVBUF,(char *)&amp;nZero,sizeof(int));

      7.一般在發送UDP數據報的時候,希望該socket發送的數據具有廣播特性:
      BOOL bBroadcast=TRUE; 
      setsockopt(s,SOL_SOCKET,SO_BROADCAST,(const 
      char*)&amp;bBroadcast,sizeof(BOOL));

      8.在client連接服務器過程中,如果處於非阻塞模式下的socket在connect()的過程中可
      以設置connect()延時,直到accpet()被呼叫(本函數設置只有在非阻塞的過程中有顯著的
      作用,在阻塞的函數調用中作用不大)
      BOOL bConditionalAccept=TRUE;
      setsockopt(s,SOL_SOCKET,SO_CONDITIONAL_ACCEPT,(const 
      char*)&amp;bConditionalAccept,sizeof(BOOL));

      9.如果在發送數據的過程中(send()沒有完成,還有數據沒發送)而調用了closesocket(),以前我們
      一般采取的措施是"從容關閉"shutdown(s,SD_BOTH),但是數據是肯定丟失了,如何設置讓程序滿足具體
      應用的要求(即讓沒發完的數據發送出去后在關閉socket)?
      struct linger {
      u_short l_onoff;
      u_short l_linger;
      };
      linger m_sLinger;
      m_sLinger.l_onoff=1;//(在closesocket()調用,但是還有數據沒發送完畢的時候容許逗留)
      // 如果m_sLinger.l_onoff=0;則功能和2.)作用相同;
      m_sLinger.l_linger=5;//(容許逗留的時間為5秒)
      setsockopt(s,SOL_SOCKET,SO_LINGER,(const 
      char*)&amp;m_sLinger,sizeof(linger));
      Note:1.在設置了逗留延時,用於一個非阻塞的socket是作用不大的,最好不用;2.如果想要程序不經歷SO_LINGER需要設置SO_DONTLINGER,或者設置l_onoff=0;

      10.還一個用的比較少的是在SDI或者是Dialog的程序中,可以記錄socket的調試信息:
      (前不久做過這個函數的測試,調式信息可以保存,包括socket建立時候的參數,采用的
      具體協議,以及出錯的代碼都可以記錄下來)
      BOOL bDebug=TRUE;
      setsockopt(s,SOL_SOCKET,SO_DEBUG,(const char*)&amp;bDebug,sizeof(BOOL));

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM