2017-06-23 146 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