【问题标题】:can't bind to socket无法绑定到套接字
【发布时间】:2016-02-09 12:38:44
【问题描述】:

代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
// #include <thread>
#include <arpa/inet.h>
#include <iostream>

using namespace std;

#define PORT 8888
#define BACKLOG 5

int main(int argc, char const *argv[]) {

    int status;
    struct addrinfo hints,
                    *res,
                    *temp;

    char ipstr [INET6_ADDRSTRLEN];
    int socket_fd;

    memset (&hints, 0, sizeof(hints));
    hints.ai_family = AF_UNSPEC;        // Allows both IPv4 and IPv6
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_PASSIVE;        // Allows automatic fill-up of IP (allows using localhost)

    if ((status = getaddrinfo (NULL , "8000", &hints, &res)) != 0 ) {
        cout << "[-] Error: " << gai_strerror (status) << endl;
        exit (EXIT_FAILURE);
    }

    socket_fd = socket (res->ai_family, res->ai_socktype, res->ai_protocol);
    if (socket_fd == -1) {
        cout << "[-] Error : Socket couldn't be created" << endl;
        exit (EXIT_FAILURE);
    }

    if (bind (socket_fd, res->ai_addr, res->ai_addrlen) == -1 ) {
        cout << "[-] Error: Failed to bind to port" << endl;
        exit (EXIT_FAILURE);
    }

    if (connect (socket_fd, res->ai_addr, res->ai_addrlen) == -1) {
        cout << "[-] Error: Failed to connect to remote user" << endl;
        exit (EXIT_FAILURE);
    }

    freeaddrinfo (res);        // free the linked list returned by getaddrinfo ()
    return 0;
}

代码正在返回:
[-] 错误:绑定端口失败

无论我在getaddrinfo() 的第一个参数(使其监听localHost)上设置NULL 还是提供一些地址,它都无法将端口绑定到套接字。正如我通过更改端口的值尝试过的那样,端口可用。代码有什么问题?

【问题讨论】:

  • 当一个函数像 e.g. bind 失败,它设置 errno。使用例如strerror 得到一个可打印的错误字符串并打印出来,你就会知道为什么调用失败了。你不应该让任何人告诉你这个,它是right there in the manual page
  • 也许使用netstat -a 来查看该端口是否在使用中
  • 谢谢。猜猜我正在测试的端口正被其他应用程序使用

标签: c++ sockets


【解决方案1】:

代码很好,所以当第一次执行时,一切都按预期工作。但是后续执行同一个程序会报错

[-] Error: Failed to bind to port

如果你运行netstat --tcp --numeric | grep 8000你会看到8000端口的socket处于TIME_WAIT状态:

bash-4.2$ netstat --tcp --numeric | grep 8000
tcp        0      0 127.0.0.1:8000          127.0.0.1:8000          TIME_WAIT

表示连接已关闭,因此它将在操作系统指定的超时时间内终止(默认为四分钟)。超时后,程序执行没有错误(再次只有一次)。

【讨论】:

    【解决方案2】:

    这里有些东西没有意义。所示代码尝试将套接字绑定到端口,然后立即将connect() 绑定到同一端口。因此,即使绑定有效,connect() 无论如何都会失败,因为该端口上没有监听任何内容。

    现在,bind() 失败的最可能原因是,在套接字意外终止后,内核在一分钟左右的时间内不允许重用相同的端口,因为许多与安全相关的原因太无聊,无法讨论。这段代码第一次运行,绑定应该成功,但是connect()会失败,程序会退出;然后在接下来的一分钟左右,重新运行它会导致内核拒绝重用端口的bind() 失败。

    为防止这种情况,您必须明确设置SO_REUSEADDR 套接字选项。您会在 Google 中找到大量示例。这将允许您立即重新绑定相同的端口。现在,您需要做的就是弄清楚您希望通过connect() 调用实现什么...

    【讨论】:

      猜你喜欢
      • 2021-11-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-10
      相关资源
      最近更新 更多