如何检查 TCP 端口是不是已被监听?
Posted
技术标签:
【中文标题】如何检查 TCP 端口是不是已被监听?【英文标题】:How do I check if a TCP port is already being listened on?如何检查 TCP 端口是否已被监听? 【发布时间】:2012-06-09 23:12:29 【问题描述】:我有一个充当 HTTP 服务器的第三方库。我向它传递了一个地址和端口,然后它用它来监听传入的连接。这个库以这样一种方式进行侦听,即它不接收端口的独占使用和它绑定的地址。结果,我可以多次监听同一个端口。
我需要在同一个进程中运行这个 HTTP 服务器的多个实例。每个实例都有一个默认端口,但如果该端口不可用,则应使用下一个可用端口。这就是我的问题所在;我可以让两个 HTTP 服务器监听同一个端口。
我无法更改 HTTP 服务器的代码,如果 HTTP 服务器无法侦听我给它的端口,它不会提醒我,因此我必须能够在启动每个 HTTP 服务器之前检查端口是否已在使用中。我尝试通过绑定我自己的套接字并将 SO_REUSEADDR 设置为 FALSE 和 SO_EXCLUSIVEADDRUSE 设置为 TRUE 来检查端口是否已经被监听,但是当现有的 HTTP 服务器已经在监听该端口时,绑定和监听调用都会成功。
这个HTTP服务器是如何实现这个效果的,如何才能准确的判断一个端口是否被这样监听?
【问题讨论】:
您是否有理由必须使用这个特定的 HTTP 服务器库?鉴于它已损坏,并且您没有足够的控制权,甚至无法弄清楚它在做什么以使其正常工作,因此切换似乎是一个非常好的主意。 出于好奇,它是哪个库? “这个库以这样一种方式进行监听,它不会接收到它所绑定的端口和地址的独占使用”。这在 TCP 中是不可能的。 TCP 中唯一可能的端口共享形式是绑定到不同的本地 IP 地址和相同的端口号。您需要重新调查,然后重新提出您的问题。 @EJP:如果不可能,这是怎么回事? i.imgur.com/7ukBb.png我可以重现这个,不管我绑定到什么地址。 @EJP:在 Windows 上,两个 TCP 套接字完全有可能绑定同一个端口。这不是有用(文档明确表示效果未定义和不确定),但它肯定会发生。 (听起来 OP 试图做的是阻止它发生,因为它没有用......虽然我承认我仍然不太清楚他的确切意图。) 【参考方案1】:使用端口号 0。操作系统将选择一个空闲端口。
【讨论】:
我无法访问 HTTP 服务器的内部套接字,所以如果我将 0 作为端口传递,我将无法取回操作系统给它的端口。 然后使用端口 0 绑定一个套接字,使用getsockaddr
发现为您选择的端口号,使用相同端口初始化 HTTP 服务器,然后关闭临时套接字。【参考方案2】:
快速而肮脏的方法是尝试将connect()
连接到本地主机上的端口。如果connect()
调用成功,那么您就知道该端口当前正在被监听(由接收连接的人监听)。如果连接调用失败(尤其是ECONNREFUSED
),那么您可以确定没有人在监听该端口。
当然,这里有一个竞争条件:在您运行上述测试之后,但在您自己绑定到端口之前,没有什么能真正阻止另一个程序突然进入并抢占端口。因此,您应该将测试结果更多地视为一种提示,而不是绝对规则,并且(希望)如果您后来发现该端口毕竟正在使用中,则可以通过某种方式处理它。
【讨论】:
他的预期测试代码将具有完全相同的竞争条件(或者,如果它有效,将具有相同的竞争条件......)。事实上,鉴于他的设计,没有办法避免它。 (上面解释了为什么我给你+1,尽管有竞争条件,不同意你的回答或类似的东西。)bind
怎么样?如果bind
使用该端口失败,则它尚未绑定。【参考方案3】:
http://msdn.microsoft.com/en-us/library/windows/desktop/ms740621(v=vs.85).aspx 解释了不同选项如何交互。
您没有向我们提供几乎足够的信息来准确地告诉我们您的用例中发生了什么,但我可以处理一个看起来像您所见的任意用例。
假设您使用的是 Win 2003 或更高版本,并且您的主 NIC 是 10.0.0.1,并且一切都在同一个用户帐户下运行。
您的应用的第一个实例出现,您的测试代码尝试将 10.0.0.1:12345 与 SO_EXCLUSIVEADDREUSE 绑定。当然,这行得通。
您关闭套接字,然后告诉 HTTP 服务器侦听端口 12345。它将 0.0.0.0:12345 与 SO_REUSEADDR 绑定,这当然有效。
现在您的应用的第二个实例出现了,您的测试代码尝试将 10.0.0.1:12345 与 SO_EXCLUSIVEADDREUSE 绑定。根据 MSDN 文章中的图表,这是可行的。
您关闭套接字,然后告诉 HTTP 服务器侦听端口 12345。它将 0.0.0.0:12345 与 SO_REUSEADDR 绑定,这是有效的。
如果这是问题所在,假设您无法让 HTTP 服务器绑定特定地址,您可以通过在测试代码中使用 0.0.0.0 来解决问题。 (当然,如果它是其他数百个可能的问题之一,则该解决方案将不起作用。)
如果你不知道 HTTP 服务器正在使用什么套接字选项、地址等,并且没有源,只需在调试器中运行它并断点相关调用即可。
【讨论】:
以上是关于如何检查 TCP 端口是不是已被监听?的主要内容,如果未能解决你的问题,请参考以下文章