2017-06-23 112 views
9

我寫了一個程序C++,我需要檢查一個TCP端口是否真空。C++檢查TCP端口

這是函數:

int checkport(char* host, char* port, int timeout) 
{ 
    int sock; 
    struct sockaddr_in sin; 
    int result = 0; 

    sock = socket(AF_INET, SOCK_STREAM, 0); 

    sin.sin_family = AF_INET; 
    sin.sin_port = htons(atoi(port)); 
    sin.sin_addr.s_addr = inet_addr(host); 
    fd_set fdset; 
    struct timeval tv; 
    fcntl(sock, F_SETFL, O_NONBLOCK); 

    int connect_result = connect(sock,(struct sockaddr*)(&sin),sizeof(struct sockaddr_in)); 
    FD_ZERO(&fdset); 
    FD_SET(sock, &fdset); 
    tv.tv_sec = timeout; 
    tv.tv_usec = 0; 

    int select_result = select(sock + 1, NULL, &fdset, NULL, &tv); 

    // printf("connect = [%d] | select = [%d]\n",connect_result,select_result); 

    if(select_result == 1) 
    { 
     int so_error; 
     socklen_t len = sizeof so_error; 
     getsockopt(sock, SOL_SOCKET, SO_ERROR, &so_error, &len); 

     // printf("so_error = [%d] \n",so_error); 

     if(so_error == 0) 
     { 
      //Is connected 
      if(hitdebug >= 4) puts("CONNECTED"); 
      if(hitdebug >= 2) printf("[%s:%s] OPEN\n",host,port); 

      result = 1; 
     } 
     else 
     { 
      if(hitdebug >= 4) puts("CONNECT_ERROR_1"); 

      result = 0; 

     } 
    } 
    else 
    { 
     if(hitdebug >= 4) puts("CONNECT_ERROR_2"); 

     result = 0; 
    } 

    close(sock); 

    return result; 
} 

的問題是,只檢測監聽端口,我希望有一個端口是100%真實,甚至檢測ESTABLISHED,TIME_WAIT等..

輸出:

connect = [-1] | select = [1] 
so_error = [111] 
50983 TEST=[0] 
tcp  0  0 1.2.3.4:50983  4.4.4.4:22  ESTABLISHED 


connect = [-1] | select = [1] 
so_error = [111] 
43343 TEST=[0] 
tcp  0  0 1.2.3.4:43343  4.4.4.4:22  ESTABLISHED 


connect = [-1] | select = [1] 
so_error = [0] 
64000 TEST=[1] 
tcp  0  0 1.2.3.4:64000  0.0.0.0:*    LISTEN 
tcp  0  0 1.2.3.4:47669  1.2.3.4:64000  TIME_WAIT 


connect = [-1] | select = [1] 
so_error = [111] 
54674 TEST=[0] 


connect = [-1] | select = [1] 
so_error = [111] 
54665 TEST=[0] 

對我來說,一個空口是當我做了netstat -an | grep 12345 | wc -l,我看到0,甚至沒有FIN_WAIT

我該如何做到這一點?

謝謝。

+0

你可能想指定你正在使用的操作系統,C++還沒有任何與標準(這是瘋狂的)相關的網絡。儘管Unix和家族之間有相似之處,但仍然存在一些差異 –

+1

只要嘗試「綁定」端口以便監聽 - 如果失敗(使用SO_REUSEADDR關閉,這是默認設置),那麼套接字或者處於主動使用或處於WAIT狀態之一。 – Useless

+1

爲什麼不解析netstat輸出? – Damien

回答

7

只需嘗試bind用於偵聽的端口 - 如果失敗(SO_REUSEADDR關閉,這是默認設置),則套接字處於活動狀態或處於WAIT狀態之一。

+0

它也會檢測到ESTAB? – Damian

+0

和我'bind()'後,我如何解除綁定和儘快釋放端口,所以我可以打開它的代理? – Damian

+0

如果'bind'成功了,你已經綁定了這個端口並且知道它是免費的,這就是你說你想要做的。如果您關閉並重新綁定港口,則存在不可避免的競爭條件。您可以安全地使用綁定端口來做的唯一事情就是直接使用它。這個代理是什麼,爲什麼你不能讓'bind'來看看它是否失敗? – Useless

15
if (the_port_is_free(port_number)) { 
    /* is the port free at this point? */ 
} 

正確的答案是「誰知道?」當然,它免費納秒前,當控制功能the_port_is_free某處,但它是免費的現在?還有很多其他的流程,也許其中一個在半秒鐘之前就把端口拿走了?

這被稱爲競賽條件。每個程序員都應該理解這個概念。

正是由於這個問題the_port_is_free不是由您的操作系統提供的:它只會給你錯誤的期望,而不是正確的答案。您現在無法知道端口是否空閒,更重要的是,您決定綁定端口時會在納秒級釋放。綁定端口的唯一方法是繼續並嘗試綁定它。

這種方法適用於一大堆情況。每當有任何類型的共享資源時,通常都沒有功能告訴你是否可以抓取它。獲得它的唯一方法是繼續嘗試。

+0

我很滿意'將在一納秒時自由',我明白你的觀點,我想做一個代理檢查器,我的問題是程序沒有檢測到'ESTABLISHED','WAIT','FIN_WAIT',理解我?一納秒或更少對我來說不是問題 – Damian

+0

@Damian不,絕對不理解你。你爲什麼需要這個?你會怎麼做的答案? –

+0

我明白賽車的概念,我只需要讓我的功能檢測ESTAB,WAIT,FIN_WAIT就完成了。現在它只偵測'LISTENING' – Damian