C ++检查TCP端口

时间:2017-06-23 13:40:48

标签: c++

我在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;
}

问题是只检测LISTEN端口,我希望端口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

我怎样才能做到这一点?

谢谢。

2 个答案:

答案 0 :(得分:15)

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

正确答案是"谁知道?"当然,当控件在函数the_port_is_free中的某个位置时, 在一个纳秒之前是免费的,但它现在是免费的吗?还有很多其他的流程,也许其中一个流程在半个纳秒之前就已经开始了?

这称为竞争条件。每个程序员都应该理解这个概念。

正是因为这个问题,你的操作系统才提供the_port_is_free:它只会给你错误的期望,而不是正确的答案。您无法知道端口现在是否空闲,更重要的是,当您决定绑定它时,它将在一纳秒内自由。绑定端口的唯一方法是继续尝试绑定它。

这种方法适用于一大堆情况。只要有任何类型的共享资源,通常没有任何功能可以告诉您是否可以抓住它。获得它的唯一方法是继续尝试。

答案 1 :(得分:7)

尝试bind端口进行侦听 - 如果失败(关闭SO_REUSEADDR,这是默认设置),则套接字处于活动状态或处于其中一种WAIT状态。