【问题标题】:Why no error when setting socket send/receive buffer size higher than sysctl max?为什么将套接字发送/接收缓冲区大小设置为高于 sysctl max 时没有错误?
【发布时间】:2018-03-17 10:22:19
【问题描述】:

为什么在设置大于 sysctl max 的套接字发送/接收缓冲区大小时没有错误(如下所示)? “预期的行为”没有错误吗?


我的套接字 rmem_maxwmem_maxsysctl 值都设置为 212992:

net.core.rmem_default = 212992
net.core.rmem_max = 212992
net.core.wmem_default = 212992
net.core.wmem_max = 212992
net.ipv4.tcp_rmem = 4096    87380   6291456
net.ipv4.tcp_wmem = 4096    16384   4194304
net.ipv4.udp_rmem_min = 4096
net.ipv4.udp_wmem_min = 4096
vm.lowmem_reserve_ratio = 256   256 32

当我创建一个套接字并尝试将套接字缓冲区大小设置为 64*1024*1024(大于rmem_maxwmem_max 的值)以进行发送/接收时:

#include <cstdlib>
#include <cstring>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/format.hpp>

using boost::asio::ip::udp;
using boost::format;
using namespace std;

int main()
{
    try
    {
        boost::asio::io_service io_service;
        udp::socket socket(io_service, udp::endpoint(udp::v4(), 0));
        udp::resolver resolver(io_service);
        udp::resolver::query query(udp::v4(), "localhost", "7770");
        udp::resolver::iterator iterator = resolver.resolve(query);

        boost::system::error_code error_code;
        socket.set_option(boost::asio::socket_base::send_buffer_size(64*1024*1024), error_code);
        cout << error_code << endl;
        boost::asio::socket_base::send_buffer_size send_buffer_size;
        socket.get_option(send_buffer_size);
        cout << format("send_buffer_size=%s") % send_buffer_size.value() << endl;

        socket.set_option(boost::asio::socket_base::receive_buffer_size(64*1024*1024), error_code);
        cout << error_code << endl;
        boost::asio::socket_base::receive_buffer_size receive_buffer_size;
        socket.get_option(receive_buffer_size);
        cout << format("receive_buffer_size=%s") % receive_buffer_size.value() << endl;
    }
    catch (std::exception& e)
    {
        std::cerr << "Exception: " << e.what() << "\n";
    }

    return 0;
}

我预计会看到一个错误,但我没有收到任何错误:

system:0
send_buffer_size=212992
system:0
receive_buffer_size=212992

如果设置缓冲区大小不报告错误是setsockopt() 的“预期行为”,我想适当的代码是在调用setsockopt() 后始终检查该值并引发我自己的错误或警告。

【问题讨论】:

  • 这些选项的行为没有标准化。您必须实现特定于您支持的每个平台的行为。从历史上看,有些平台您几乎不会读回您设置的相同尺寸,因为它们测量尺寸的方式与设置它们的方式不同。
  • 我一直都知道,虽然现在找不到写在哪里,但系统可以上下调整你指定的大小,你需要调用getsockopt()来了解实际的分配是。

标签: c++ c sockets sysctl setsockopt


【解决方案1】:

为什么将套接字发送/接收缓冲区大小设置为高于 sysctl max 时没有错误(如下所示)? “预期的行为”没有错误吗?

POSIX 没有明确说明这一点。在无法为有效选项设置指定值的情况下,它确实允许 setsockopt() 失败(返回-1 并设置errno),但这种情况不在其中它要求实现失败。特别是,如果您参考the specifications,您将不会在setsockopt() 的故障条件列表中找到您的方案。最接近的似乎是“指定的选项在指定的套接字级别无效或套接字已关闭”,但在指定的套接字级别无效只能应用于选项本身,而不是为它指定的值。

此外,its description of the receive buffer and send buffer options 将它们特别描述为 请求 以设置指定的缓冲区大小。例如:

SO_RCVBUF 选项请求分配的缓冲区空间 将此套接字上的接收操作设置为以字节为单位的值 期权价值。 [...]

大多数其他选项的描述更具确定性,通常使用动词“sets”而不是“requests”。也许我读得太多了,但对我来说,如果这是一个请求,那么实现就不一定会尊重它。 setsockopt() 的成功与否取决于它是否传递请求,而不是请求是否被接受。

你说:

如果设置缓冲区大小不报错是“预期 行为”对于setsockopt(),我想适当的代码是 在调用setsockopt() 后总是检查值并提高我自己的值 错误或警告。

如果您希望报告setsockopt() 无法设置您指定的确切缓冲区大小,那么您确实应该能够通过getsockopt() 将它们读回以进行检查。 POSIX 指定这些特定选项的值表示缓冲区大小以字节为单位;因此,在符合要求的实现中,提供给setsockopt 的值与通过getsockopt 获得的值相当。

不过,您可能会感到惊讶。我可以想象有几个一致的变体,如果两者不能完全匹配是常规的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-02
    • 2018-07-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-11-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多