【问题标题】:::socket returns 0 and ::connect sets errno to EBADF::socket 返回 0 并且 ::connect 将 errno 设置为 EBADF
【发布时间】:2012-05-21 19:28:11
【问题描述】:

我正在使用 BSD 套接字,我想使用 ::connect 连接到端口 80 上的 example.com::socket 的手册页告诉我它返回一个有效的文件描述符,或者 -1 on错误。

auto fd = ::socket(AF_INET, SOCK_STREAM, 0);

struct ::sockaddr_in addr;
::bzero(&addr, sizeof(addr));
addr.sin_family = family_;

struct ::hostent* hostent = ::gethostbyname(host.c_str());
::bcopy(hostent->h_addr, &addr.sin_addr.s_addr, hostent->h_length);
addr.sin_port = port;

auto err = ::connect(fd,
                     reinterpret_cast<struct ::sockaddr*>(&addr),
                     sizeof(addr));

fd == 0,所以::socket 成功(否则它会返回-1)。但是err == -1errno设置为EBADF,说明fd是一个错误的文件描述符。

这里会发生什么?为什么::connect 告诉我我给了它一个错误的文件描述符,而我显然没有?

【问题讨论】:

    标签: c++ sockets


    【解决方案1】:

    您应该确认socket 实际上返回 0?除非您关闭了标准文件描述符,否则这将是非常不寻常的。确保在套接字调用后立即检查它,以防它被其他调用破坏。

    【讨论】:

    • std::cout &lt;&lt; ::socket(AF_INET, SOCK_STREAM, 0) &lt;&lt; '\n'; 打印 0。如果我在调用::socket 后设置断点,fd == 0 会告诉我的调试器。我没有关闭标准文件描述符,afaik。
    • 嗯,看来我不小心关闭了文件描述符0
    【解决方案2】:

    尝试将第三个参数显式地作为 IPPROTO_TCP 传递给 ::socket() 调用。

    auto fd = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    

    “0”值是 IPPROTO_IP,这不是您需要的。

    另一个猜测:尝试设置

    addr.sin_addr = htons(port);
    

    您可能正在连接不可用的东西(端口不是 80,如您所料,而是 0x5000 == 20480)。

    第三次尝试。您正在使用 BSD/MacOS、Linux 或其他 POSIX 系统?还是 WinSock ?如果是 windows,请检查 WSAStartup 调用。

    【讨论】:

    • 试试 addr.sin_port = htons(port);
    • @Radek'daknok'Slupik:你必须使用htons
    • @ViktorLatypov:“指定协议 0 会导致 socket() 使用适用于请求的套接字类型的未指定默认协议”(对于流套接字来说是 TCP)。
    猜你喜欢
    • 1970-01-01
    • 2015-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-06
    • 2010-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多