5

我有一个充当 HTTP 服务器的第三方库。我将一个地址和端口传递给它,然后它用它来监听传入的连接。这个库以这样一种方式进行侦听,即它不接收端口的独占使用和它绑定到的地址。结果,我可以多次监听同一个端口。

我需要在同一个进程中运行这个 HTTP 服务器的多个实例。每个实例都有一个默认端口,但如果该端口不可用,则应使用下一个可用端口。这就是我的问题所在;我最终可以让两个 HTTP 服务器在同一个端口上侦听。

我无法更改 HTTP 服务器的代码,如果 HTTP 服务器无法侦听我给它的端口,它不会提醒我,因此我必须能够在启动每个 HTTP 服务器之前检查端口是否已在使用中。我尝试通过绑定我自己的套接字并将 SO_REUSEADDR 设置为 FALSE 和 SO_EXCLUSIVEADDRUSE 设置为 TRUE 来检查端口是否已经被监听,但是当现有的 HTTP 服务器已经在该端口上监听时,绑定和监听调用都会成功。

这个HTTP服务器是如何达到这个效果的,我怎样才能准确地检查一个端口是否正在以这种方式被监听?

4

3 回答 3

6

快速而肮脏的方法是尝试访问connect()本地主机上的端口。如果connect()调用成功,那么您就知道该端口当前正在被监听(接收连接的人)。如果连接调用失败(尤其是ECONNREFUSED),那么您可以确定没有人在监听该端口。

当然,这里有一个竞争条件:在您运行上述测试之后,但在您自己绑定到端口之前,没有什么能真正阻止另一个程序突然进入并抢占端口。因此,您应该将测试结果更多地视为一种提示,而不是绝对规则,并且(希望)如果您后来发现该端口毕竟正在使用中,则可以通过某种方式来处理它。

于 2012-06-05T22:57:40.773 回答
3

使用端口号 0。操作系统将选择一个空闲端口。

于 2012-06-05T22:21:25.503 回答
1

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 服务器正在使用哪些套接字选项、地址等,并且没有源,只需在调试器中运行它并为相关调用设置断点即可。

于 2012-06-05T23:00:55.063 回答