Как я могу найти в C, что порт свободен в использовании?

ОС - это Linux. У меня есть серверный процесс, который может изменить его порт в реальном времени. Однако я хотел бы знать заранее, если порт свободен до привязки.

Сценарий: сервер связывает localhost: 5000 и получает запрос на связывание в localhost: 6000. Сервер должен проверить, свободен ли порт. Этот вопрос требует ответов, которые предоставляют процедуру, которая проверяет, свободен ли порт или нет.

Для записи я редактирую свой вопрос с помощью фрагмента кода, который проверяет, доступен ли порт для использования. Это не означает, что он будет использоваться. В приведенном ниже коде на вопрос "если порт доступен прямо сейчас", он не использует его. Открывает сокет, проверяет, возвращает ли связь 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;


}

Вот несколько примеров прогона (частичные выходы)

[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

Ответ 1

Это очевидное условие , поскольку другие процессы в вашей системе могут быть привязаны к портам параллельно. Таким образом, любое решение, которое вы найдете, будет несовершенным, и вам все равно нужно просто написать его в соответствии с "попробуйте bind(), если он не сможет выбрать новый номер порта и повторить попытку".

Ответ 2

Если вашему серверу сообщили, какой порт использовать, просто bind() он. Серьезно.

Конечно, вы можете разобрать /proc/net/tcp и посмотреть, используется ли порт. Но что тогда? Вам все равно нужно позвонить bind(), теперь, когда вы знаете, что ваш порт свободен, и он скажет вам, был ли порт свободным, так или иначе, и поэтому не было смысла пресмыкаться через /proc/net/tcp и делать все это (медленно! ) строковое производство и синтаксический анализ, а также дополнительные отключения ядра с помощью не очень оптимизированных (читай: супер медленных по сравнению с bind()) диагностических путей, чтобы получить информацию, которая может быть устаревшей, прежде чем вы даже закончите ее разбор. Поэтому просто позвоните bind() и будьте счастливы.

Ответ 3

Я боролся с этим сам и немного изменил ваш код.

Решение состоит в том, чтобы установить serv_addr.sin_port = 0 (автоматически назначить порт).

Примечание В строках 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;
}

Программный выход

Opened 4
port number 59081