Linux 我如何在 C 中找到一个可以免费使用的端口?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10294515/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 05:57:47  来源:igfitidea点击:

how do I find in C that a port is free to use?

clinuxsocketsnetwork-programming

提问by cateof

The OS is Linux. I have a server process that can change its port realtime. However I would like to know in advance if a port is free before binding.

操作系统是Linux。我有一个可以实时更改其端口的服务器进程。但是,我想在绑定之前提前知道端口是否空闲。

Scenario: Server binds localhost:5000 and receives a request to bind at localhost:6000. The server has to check if the port is free. This question seeks for answers that provide a routine that checks if a port is free or not.

场景:服务器绑定 localhost:5000 并收到绑定到 localhost:6000 的请求。服务器必须检查端口是否空闲。此问题寻求提供检查端口是否空闲的例程的答案。

For the record, I am editing my question with a code snippet that checks if a port is free to use. This does not mean that it will be used. The code below answer to the question "if the port is available right now", it does not use it. Opens a socket, check if bind returns EADDRINUSE and closes the socket.

作为记录,我正在使用检查端口是否可以免费使用的代码片段来编辑我的问题。这并不意味着它将被使用。下面的代码回答了“如果端口现在可用”这个问题,它不使用它。打开一个套接字,检查 bind 是否返回 EADDRINUSE 并关闭套接字。

#include <iostream>
#include <sys/socket.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>

int main(int argc, char **argv) {

    struct sockaddr_in serv_addr;
    if( argc < 2 )
        return 0;
    int port = atoi(argv[1]);

    int sockfd = socket(AF_INET, SOCK_STREAM, 0);
    if( sockfd < 0 ) {
        printf("socket error\n");
        return 0;
    } else {
        printf("Opened fd %d\n", sockfd);
    }

     bzero((char *) &serv_addr, sizeof(serv_addr));
     serv_addr.sin_family = AF_INET;
     serv_addr.sin_addr.s_addr = INADDR_ANY;
     serv_addr.sin_port = htons(port);
     if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {

        if( errno == EADDRINUSE )
        {
            printf("the port is not available. already to other process\n");
        } else {
            printf("could not bind to process (%d) %s\n", errno, strerror(errno));
        }
    }

    if (close (sockfd) < 0 ) {
        printf("did not close fd: %s\n", strerror(errno));
        return errno;
    }

    return 0;


}

Here are some sample runs (partial outputs)

以下是一些示例运行(部分输出)

[bash{1051}{51}]:[~/some_sources/checkbind]::./a.out 41067
the port is not available. already to other process
[bash{1052}{52}]:[~/some_sources/checkbind]::./a.out 22
could not bind to process (13) Permission denied
[bash{1053}{53}]:[~/some_sources/checkbind]::./a.out 22000
Opened fd 3

采纳答案by unwind

This is an obvious race condition, since other processes on your system might be binding to ports in parallel. So, any solution you find will be imperfect, and you will stillneed to just write it according to the "try to bind(), if it fails pick a new port number and try again" approach.

这是一个明显的竞争条件,因为您系统上的其他进程可能并行绑定到端口。因此,您找到的任何解决方案都是不完美的,您仍然需要根据“尝试bind(),如果失败,请选择一个新的端口号并重试”的方法来编写它。

回答by bdonlan

If your server was toldwhat port to use, just bind()it. Seriously.

如果您的服务器被告知要使用哪个端口,就bind()可以了。严重地。

Sure, you could parse /proc/net/tcpand see if the port's in use. But then what? You still need to call bind()now that you know your port is free, and it'll tell you if the port was free then anyway, and so there was no point in groveling through /proc/net/tcpand doing all that (slow!) string production and parsing and extra kernel trips through not-very-well-optimized (read: super slow compared to bind()) diagnostic paths, just to get information that could well be out of date before you even finished parsing it. So just call bind()and be happy.

当然,您可以解析/proc/net/tcp并查看端口是否正在使用中。但是然后呢?bind()现在您仍然需要打电话,因为您知道您的端口是免费的,并且无论如何它都会告诉您该端口是否空闲,因此没有必要埋头苦干/proc/net/tcp并执行所有这些(慢!)字符串生成和解析以及额外的内核会通过不是很好优化(阅读:与 相比超慢bind())诊断路径,只是为了在您完成解析之前获取可能已经过时的信息。所以只要打电话bind()就开心。

回答by neoneye

I struggled with this myself and have slightly modified your code.

我自己为此苦苦挣扎,并稍微修改了您的代码。

The solution is to set serv_addr.sin_port = 0(auto assign port).

解决方法是设置serv_addr.sin_port = 0(自动分配端口)。

NoteIn the bind()and the getsockname()lines there are unclean casts from sockaddr_into sockaddr. I have seen it done many places and I'm looking for a safer solution.

注意bind()getsockname()行中有从sockaddr_in到 的不干净的强制转换sockaddr。我已经看到它在很多地方完成,我正在寻找更安全的解决方案。

#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>

// ... snip ...

int sock = socket(AF_INET, SOCK_STREAM, 0);
if(sock < 0) {
    printf("socket error\n");
    return;
}
printf("Opened %d\n", sock);

struct sockaddr_in serv_addr;
bzero((char *) &serv_addr, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = 0;
if (bind(sock, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < 0) {
    if(errno == EADDRINUSE) {
        printf("the port is not available. already to other process\n");
        return;
    } else {
        printf("could not bind to process (%d) %s\n", errno, strerror(errno));
        return;
    }
}

socklen_t len = sizeof(serv_addr);
if (getsockname(sock, (struct sockaddr *)&serv_addr, &len) == -1) {
    perror("getsockname");
    return;
}

printf("port number %d\n", ntohs(serv_addr.sin_port));


if (close (sock) < 0 ) {
    printf("did not close: %s\n", strerror(errno));
    return;
}

Program output

程序输出

Opened 4
port number 59081