【问题标题】:Find out whether tcp port is bound (not listening) using bash使用 bash 查明 tcp 端口是否已绑定(未侦听)
【发布时间】:2015-06-07 07:17:52
【问题描述】:

我正在尝试确定最近启动的进程绑定的 TCP 端口是否实际上被该特定进程使用。

获取这个program.cpp

int daemonport = 11234;

struct sockaddr_in loopback;
memset ((char*) &loopback, 0, sizeof (loopback));
socklen_t len = sizeof (loopback);
loopback.sin_family = AF_INET;
loopback.sin_port = htons (daemonport);
loopback.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
daemonfd = socket (AF_INET, SOCK_STREAM, 0);
if (daemonfd < 0)
{
    errx (EXIT_FAILURE, "Critical error");
}
if (bind (daemonfd, (struct sockaddr*) &loopback, sizeof (loopback)) != 0)
{
    errx (EXIT_FAILURE, "Daemon already running, TCP port: '%d'", daemonport);
}
if (getsockname (daemonfd, (struct sockaddr*) &loopback, &len) != 0)
{
    errx (EXIT_FAILURE, "Critical error");
}
printf ("%d\n", ntohs (loopback.sin_port));

if (daemon (1, 0) < 0)
{
    close (daemonfd);
    errx (EXIT_FAILURE, "Failed to daemonize!");
}

// event loop...

close (daemonfd);

现在将 tcp 套接字绑定(但未侦听)到端口 11234,我想使用 bash 脚本检查该端口是否被进程绑定。

我尝试了各种 netstat 和 lsof 模式都没有成功:

netstat -a | grep ':11234' 以及 lsof -i :11234

他们都不用绑定的端口打印一行。

但是当我第二次尝试运行该程序时,它会出错:

Daemon already running, TCP port: '11234'

【问题讨论】:

    标签: linux bash sockets tcp


    【解决方案1】:

    假设是 Linux,从这个开始:

    netstat --inet -n -a -p | grep ':myport'

    看看你得到了什么。 --inet 不显示 IP6 和 Unix 域套接字。 -n 显示的是数字结果,而不是从端口号转换而来的名称。 -p 告诉你哪个进程正在监听它。

    如果这些行中的任何一行显示“LISTEN”,那么一个进程正在该端口上侦听。但是,任何使用该端口的打开连接(甚至是“TIME_WAIT”)都会阻止重新打开该端口,除非您每次绑定时都使用SO_REUSEPORT option

    如果该命令没有向您显示任何内容,则说明该端口上没有监听任何内容,这意味着您的程序一定有问题。

    您正在打印一条错误消息,但假设问题已经在运行。打印出errno 值(使用perror(...)),这样您就可以确切地知道问题所在。

    【讨论】:

    • 如果我为绑定错误添加perror(...),它会按预期打印Address already in use。那是当我尝试运行程序时,它的另一个实例已经绑定到端口。 netstat --inet -n -a -p | grep ':11234' 除了不是 root 的常规信息外,不显示任何内容。
    • 如果有东西在使用该端口,netstat 会显示它。如果你最近运行过你的程序,使用过,退出过,现在它不会再次运行,这是一个 SO_REUSE 问题。
    • 关键是程序仍在运行,因此套接字没有关闭,第二个实例无法绑定到同一个端口,这正是我想要实现的。但是,netstat 没有显示与该端口关联的程序。 SO_REUSEPORT 在我的 debian 操作系统上似乎不可用。如果我设置SO_REUSEADDR 而不是第二个实例在绑定时不会出错,这是有道理的,但这不是我想要的。
    • 事实上:一旦我终止第一个实例,套接字就会关闭,一旦我再次运行程序,它就不会出错。我要说的是端口绑定似乎确实可以正常工作。
    • 当您的程序退出时,所有套接字都将关闭,但这并不意味着它们不再存在。 TCP 将经历其关闭阶段,该阶段通常包括几分钟的“TIME_WAIT”,用于先前建立的连接,在此期间端口号仍在“使用中”(除非您使用 SO_REUSEPORT)尝试再次绑定它。跨度>
    【解决方案2】:

    例如,检查端口 56789 是否在本地可用:

    port=56789
    retval=$(python3 -c 'import socket; s=socket.socket(); s.bind(("", '"${port}"')); print(s.getsockname()[1]); s.close()' 2>/dev/null)
    echo "$retval"
    

    如果端口已经绑定,这将打印一个空行,如果未绑定,则打印 56789。如果端口 56789 最近被使用并关闭,但 TIME_WAIT 时间尚未过去(通常为一两分钟),则该端口将不可用,并且上述代码不会回显 56789。

    我意识到这有点作弊,因为它也使用 python,但如果 python 3 可用,它是 bash 可编写脚本的。不需要 sudo。

    【讨论】:

      猜你喜欢
      • 2012-10-29
      • 2012-06-09
      • 1970-01-01
      • 2023-03-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-03
      • 2015-11-29
      相关资源
      最近更新 更多