【问题标题】:Outgoing TCP port matches listening port传出 TCP 端口与侦听端口匹配
【发布时间】:2010-12-08 22:34:43
【问题描述】:

我遇到了一个奇怪的偶然事件,我的结果是

lsof | grep 40006

生产

java      29722     appsrv   54u     IPv6           71135755        0t0      TCP localhost:40006->localhost:40006 (ESTABLISHED)

一般我会看到

java      30916     appsrv   57u     IPv6           71143812        0t0      TCP localhost:43017->localhost:40006 (ESTABLISHED)

箭头两侧的端口不匹配。当 lsof 产生前一个结果时,即使套接字配置为 SO_REUSEADDR,我也无法启动尝试侦听端口 40006 的应用程序。

这会发生吗?应该吗?

uname 给出:Linux femputer 2.6.32-24-server #39-Ubuntu SMP Wed Jul 28 06:21:40 UTC 2010 x86_64 GNU/Linux

【问题讨论】:

  • 注意:对于第一个 lsof 结果,监听 40006 的应用程序被终止了。

标签: linux sockets tcp lsof


【解决方案1】:

可以通过创建一个套接字来安排这样的连接,将其绑定到127.0.0.1:40006,然后将connect() 绑定到127.0.0.1:40006。 (注意:没有listen())。我相信这被称为“主动-主动打开”。

以下程序演示了这一点:

#include <stdio.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <unistd.h>

int main()
{
    int s;
    struct sockaddr_in sa = {
        .sin_family = PF_INET,
        .sin_port = htons(40006),
        .sin_addr.s_addr = htonl(INADDR_LOOPBACK) };

    s = socket(PF_INET, SOCK_STREAM, 0);

    if (s < 0) {
        perror("socket");
        return 1;
    }

    if (bind(s, (struct sockaddr *)&sa, sizeof sa) < 0) {
        perror("bind");
        return 1;
    }

    if (connect(s, (struct sockaddr *)&sa, sizeof sa) < 0) {
        perror("connect");
        return 1;
    }

    pause();

    return 0;
}

端口不能被重用的原因是端口没有监听——它是一个传出端口。

【讨论】:

  • 我从第二个 lsof 输出中遗漏了一些我现在后悔的东西。第一个 lsof 结果是完整的打印输出。整个第二个是
  • java 30916 appsrv 57u IPv6 71143812 0t0 TCP localhost:43017->localhost:40006 (ESTABLISHED) \n myapp 30957 appsrv 4u IPv4 71143810 0t0 TCP *:40006 (LISTEN) \n myapp 30957 appsrv 5u 71143811 0t0 TCP localhost:40006->localhost:43017 (ESTABLISHED) 对于第一个 lsof 结果的情况,myapp 当时被终止,并且在我发现我无法重新启动它之后显示的行仍然存在。也许 myapp 没有完全关闭?我会检查关机代码。
  • 我假设 localhost:43017->localhost:40006 部分的左侧是随机的,我不知道要搜索什么来找出其中的因素。我认为会有防止重叠的机制,但如果默认情况下不启用它们,我不知道它们是什么。
  • @user535674:如果服务器没有运行,也可能是 client 应用程序(通常执行connect() 的应用程序)无意中创建了循环当它尝试连接时。无论如何,some 应用程序仍在运行并保持该连接打开(在您的示例中为 PID 2972​​2)。 (有机制来阻止这种情况——只有当你的应用程序在我的示例C代码中在connect()之前专门执行bind()时才会发生这种情况。我怀疑你的客户端应用程序错误地使用了bind()) .
  • 客户端应用程序使用 java Socket 构造函数 new java.net.Socket(host, port),其中 host 是 String,port 是 int。根据 JVM 源代码,该调用将绑定到本地端口 0,它应该选择一个空闲端口号。我想这次没有。
【解决方案2】:

会不会是这两个40006 端口在不同的接口上?

【讨论】:

  • 电脑上只有一个接口。
  • 除非区分 lo 和 eth0,因为这两个应用程序都在同一台计算机上并通过主机名 localhost 连接。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-29
  • 1970-01-01
  • 1970-01-01
  • 2021-02-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多