天天看點

linux下socket常見問題整理

1. socket不能立即關閉的問題

每次修改了源代碼并再次編譯運作時,常遇到下面的錯誤:

Cann't bind server socket !
Address already in use
           

解決方法為使用setsockopt函數設定SO_REUSEADDR,示例代碼如下:

int reuse = 0;
struct sockaddr_in cliaddr, servaddr;
listenfd = socket(PF_INET, SOCK_STREAM,0);
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
    perror("setsockopet error\n");
    return -1;
}
           

2. 關于tcp用戶端非正常掉線的問題

開啟探測屬性,在一段時間内沒有資料往來,則發送探測包,若探測包收得不到響應,則重發一定次數,若還未得到響應則認為鍊路斷開,示例代碼如下:

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>

int keepAlive = 1; // 開啟keepalive屬性
int keepIdle = 60; // 如該連接配接在60秒内沒有任何資料往來,則進行探測 
int keepInterval = 5; // 探測時發包的時間間隔為5 秒
int keepCount = 3; // 探測嘗試的次數.如果第1次探測包就收到響應了,則後2次的不再發.

setsockopt(rs, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
setsockopt(rs, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
setsockopt(rs, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
setsockopt(rs, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));
ioctl(s, FIONBIO, &non_blocking);/*設定非堵塞*/
           

3. socket用戶端關閉檢測

方式1:當使用 select()函數測試一個socket是否可讀時,如果select()函數傳回值為1,且使用recv()函數讀取的資料長度為0 時,就說明該socket已經斷開,示例代碼:

if(FD_ISSET(net->desfd,&tempset)) {
    char recvbuf[1024] = {0};
    int ret = read(net->desfd, recvbuf, 1024);
    if (ret == -1)
        ERR_EXIT("readline error");
    else if (ret == 0) { //用戶端關閉
        printf("client %d close \n",net->desfd);
        FD_CLR(net->desfd, &mset);
        client[i] = -1;
        close(net->desfd);
    }
}
           

方式2:用getsockopt來判斷,示例代碼:

#include <linux/types.h>
#include <asm/byteorder.h>
#include <linux/config.h>
#include <linux/skbuff.h>
#include <linux/ip.h>
#include <net/sock.h>

int SocketConnected(int sock)
{
    if (sock <= 0)
        return 0;
    struct tcp_info info;
    int len = sizeof(info);
    getsockopt(sock, IPPROTO_TCP, TCP_INFO, &info, (socklen_t *) & len);
    if ((info.tcpi_state == TCP_ESTABLISHED)) {
        //myprintf("socket connected\n"); 
        return 1;
    } else {
        //myprintf("socket disconnected\n"); 
        return 0;
    }
}
           

4. 關于指定用戶端ip的問題

對于伺服器來說,設定指定ip位址的通路,主要是通過accept函數傳回的用戶端的ip和端口号來判斷,若不是所設定的則進行關閉操作。

用戶端在連接配接時,也可指定自己的ip位址(同伺服器),在connet連接配接之前通過bind綁定。

cln->srcaddr.sin_family = AF_INET;
cln->srcaddr.sin_port = htons(5555);
cln->srcaddr.sin_addr.s_addr = inet_addr("192.166.0.222");
bind(cln->srcfd, (struct sockaddr *)&(cln->srcaddr), sizeof(cln->srcaddr))
           

繼續閱讀