c++ 如何在MacOS上获取选项,如果套接字设置为侦听?

1l5u6lss  于 2023-04-08  发布在  Mac
关注(0)|答案(1)|浏览(136)

我使用一个简单的googletest来获取套接字是否被设置为监听。套接字级别SO_ACCEPTCONN上有一个选项,它显示套接字有一个listen()调用。

TEST(SocketTestSuite, check_listen) {
    int sockfd = socket(AF_INET6, SOCK_STREAM, 0);
    ASSERT_NE(sockfd, INVALID_SOCKET);

    int so_option = 987654321;
    socklen_t optlen{sizeof(so_option)};
    int ret = getsockopt(sockfd, SOL_SOCKET, SO_ACCEPTCONN, &so_option, &optlen);

    if (ret != 0) {
        perror("Error getsockopt");
    }
    EXPECT_EQ(so_option, 0);
}

在Linux上,我得到了预期的结果:套接字未设置为侦听。

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from SocketTestSuite
[ RUN      ] SocketTestSuite.check_listen
[       OK ] SocketTestSuite.check_listen (0 ms)
[----------] 1 test from SocketTestSuite (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 1 test.

在MacOS上,我得到:

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from SocketTestSuite
[ RUN      ] SocketTestSuite.check_listen
Error getsockopt: Protocol not available
/Users/runner/work/client-server-tcp/client-server-tcp/test_client-server-tcp.cpp:165: Failure
Expected equality of these values:
  so_option
Which is: 987654321
  0

[  FAILED  ] SocketTestSuite.check_listen (0 ms)
[----------] 1 test from SocketTestSuite (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] SocketTestSuite.check_listen

为什么会抱怨**“Protocol not available”**?什么协议?SO_ACCEPTCONN是一个socket选项。不管怎么样,如果我使用TCP协议6:

int ret = getsockopt(sockfd, 6, SO_ACCEPTCONN, &so_option, &optlen);

我得到这个结果:

[==========] Running 1 test from 1 test suite.
[----------] Global test environment set-up.
[----------] 1 test from SocketTestSuite
[ RUN      ] SocketTestSuite.check_listen
/Users/runner/work/client-server-tcp/client-server-tcp/test_client-server-tcp.cpp:164: Failure
Expected equality of these values:
  so_option
    Which is: 1024
  0

[  FAILED  ] SocketTestSuite.check_listen (0 ms)
[----------] 1 test from SocketTestSuite (0 ms total)

[----------] Global test environment tear-down
[==========] 1 test from 1 test suite ran. (0 ms total)
[  PASSED  ] 0 tests.
[  FAILED  ] 1 test, listed below:
[  FAILED  ] SocketTestSuite.check_listen

MacOS现在对它的协议很满意,但它显示so_option = 1024trueas option!= 0。这是错误的。套接字没有设置为侦听。1024是0x 400,看起来像一个位设置选项,但我不知道为什么会给出这个选项。
这是怎么回事?为什么MacOS不能像Linux那样正常工作?
参考文献:
Mac OS X standard socket.h file
getsockopt() — Get the options associated with a socket

mfpqipee

mfpqipee1#

“Protocol not available”是ENOPROTOOPT的文本错误消息,当您尝试使用“unknown at the level indicated”的(get|set)sockopt()选项时,errno会报告此消息。
换句话说,这意味着MacOS告诉你它不识别SOL_SOCKET级别的SO_ACCEPTCONN选项。这是有道理的,因为根据Apple的OSX文档(并通过各种在线来源确认),getsockopt()setsockopt()不支持SO_ACCEPTCONN选项。
SO_ACCEPTCONN的数值为2。通过将级别设置为6IPPROTO_TCP),您将向getsockopt()请求TCP选项2,即TCP_MAXSEG(传出TCP数据包的最大段大小)。
因此,您需要相应地调整您的测试:

TEST(SocketTestSuite, check_listen) {
    int sockfd = socket(AF_INET6, SOCK_STREAM, 0);
    ASSERT_NE(sockfd, INVALID_SOCKET);

    int so_option = 0;
    socklen_t optlen = sizeof(so_option);

    int ret = getsockopt(sockfd, SOL_SOCKET, SO_ACCEPTCONN, &so_option, &optlen);
    if (ret < 0) {
        if (errno != ENOPROTOOPT)
            FAIL() << "Error getsockopt: " << strerror(errno);
        else
            FAIL() << "Option not supported by getsockopt";
    }
    else {
        EXPECT_EQ(so_option, 0);
    }

    close(sockfd);
}

AFAIK,没有其他的getsockopt()选项可以替代SO_ACCEPTCONN。我知道的测试套接字是否在监听的唯一方法是使用accept(),如果在没有监听的套接字上调用EINVAL,它将失败。

相关问题