服務端socket重用屬性設置


初始化socket

socket是一種系統資源,並不是每次初始化都一定成功,因此為了避免初始化失敗,一般使用多次初始化的方式,如下所示:

unsigned int times = 0x0;
while((server = socket(PF_INET6, SOCK_STREAM, 0)) < 0 && times < 0x3)
{       
    times++;
    printf("create socket faild %d times\n", times);
}

設置socket的可重用屬性

一般來說,一個端口釋放后需要等待兩分鍾左右才能被再次使用,SO_REUSEADDR是讓端口釋放后立即就可以被再次使用。例如:一個進程監聽一個端口,進程在某個時候異常重啟了,如果socket沒有設置可重用屬性,那么進程重啟后就會出現bind錯誤,因為同一個端口兩次監聽的時間間隔需要75秒;如果設置了可重用屬性,那么同一個端口釋放之后馬上就可以再次使用,如下所示:

int reuse = 0x0;
result = setsockopt(server, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(int));
if(result != 0)
{
    printf(" Fail to set socket reuseraddr options, errno = 0x%x!\n", result);
}

設置socket的保活屬性

TCP是一種面向連接的協議,因此需要實時檢查連接是否正常,特別是在上層長時間無數據傳輸時。一般檢查連接是否正常的方式是提供一個保活機制,即定時的發送一種探測報文,可以是上層自己發送,也可以使用socket自己提供的保活機制,也就是保活屬性,但是socket自己提供的保活機制一般不可靠,或者說是不完全可靠,因此在實際編程中是兩種同時使用。首先上層啟用一個任務,定時發送檢測報文,然后設置socket的保活屬性,以期達到完全可靠,如下所示:

int optval = 0x1;
result = setsockopt(server, SOL_SOCKET, SO_KEEPALIVE, (char*)&optval, sizeof(int));
if(result != 0)
{
    printf("Fail to set socket keepalive options, errno = 0x%x!\n", result);
}

設置socket的緩沖區大小屬性

調用send和recv接口操作數據時,是直接將數據拷貝到緩沖區或是從緩沖器拷貝數據,如果緩存區滿了,溢出后就會丟失數據,因此合理的設置緩存區的大小很重要,注意發送緩沖區和接收緩沖區是兩個緩存區,不是同一個。如下所示:

int BufSize = 32 * 1024;
result = setsockopt(iSocketServer, SOL_SOCKET, SO_SNDBUF, (CHAR *)&BufSize, sizeof(BufSize));
if(result!= 0)
{
    printf("Fail to set socket sendbuf options, errno = 0x%x!\n", result);
}

int BufSize = 32 * 1024;
result = setsockopt(iSocketServer, SOL_SOCKET, SO_RCVBUF, (CHAR *)&BufSize, sizeof(BufSize));
if(result != 0)
{
    printf("Fail to set socket recvbuf options, errno = 0x%x!\n", result);
}

綁定socket

如果socket作為服務端,那么必須的操作是綁定一個IP,且綁定時並不是一定就會成功,因此使用多次綁定的方法,如下所示:

struct sockaddr_in6 ServerIp_V6 = {0x0};

memset(&ServerIp_V6, 0x0, sizeof(struct sockaddr_in6));
ServerIp_V6.sin6_family = AF_INET6;
ServerIp_V6.sin6_port   = htons(9999);
ServerIp_V6.sin6_addr   = in6addr_any;

times = 0;
while((result = bind(server, (struct sockaddr *)&ServerIp_V6, sizeof(struct sockaddr_in6))) != 0 && times < 0x3)
{
    times++;
    printf("Bind socket faild %d times\n", times);    
}

 監聽socket

同綁定socket的操作,注意最大監聽個數的選擇,如下所示:

times = 0;
listenMax = 0x10;
while ((lResultCode = listen(server, listenMax)) != 0 && times < 0x3)
{
    times++;
    printf("[tkQxPotnDaemon] listen socket faild %d times\n", times);
}

等待客戶端連接

服務端一切設置好之后,就需要調用accpet阻塞式等待客戶端來連接,如下所示:

struct sockaddr_in6 ManagerIp_v6 = {0x0};
int AddrLen = sizeof(struct sockaddr_in6);
while(1)
{
    memset(&ManagerIp_v6, 0x0, sizeof(struct sockaddr_in6));
    AcceptSocket = accept(server, (struct sockaddr *)&ManagerIp_v6, (socklen_t *)&AddrLen);
    if (AcceptSocket < 0)
    {
        continue;
    }
    
    // 注意:ip是ManagerIp_v6.sin6_addr中的12、13、14、15位
    // 如:ManagerIp_v6.sin6_addr[12]、ManagerIp_v6.sin6_addr[13]、ManagerIp_v6.sin6_addr[14]、ManagerIp_v6.sin6_addr[15]
    
    // 注意:端口號是htons(ManagerIp_v6.sin6_port)
    
    // 進行數據通信
}


免責聲明!

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



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