我在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
我怎样才能做到这一点?
谢谢。
答案 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状态。