linux 内核参数的实际作用的疑惑?

发布于 2022-09-11 22:18:01 字数 5380 浏览 28 评论 0

"tcp 内核接收和发送缓冲区"
sysctl -x net.ipv4.tcp_mem   -> net.ipv4.tcp_rmem = 4096   87380  6291456
sysctl -x net.ipv4.tcp_rmem  -> net.ipv4.tcp_wmem = 4096   16384  4194304
--------------------------------------------------------------
"本地测试"
--------------------------------------------------------------
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void print_buffer(const int &fd) {
    int buffer_size = 0;
    socklen_t opt_len = sizeof(buffer_size);
    if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, &opt_len) == 0) {
        std::cout << "send buffer = " << buffer_size << std::endl;
    }
    if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, &opt_len) == 0) {
        std::cout << "recv buffer = " << buffer_size << std::endl;
    }
}

int main(int argc, char* argv[]) {
    int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    print_buffer(fd);
    return 0;
}
"运行结果 与 内核参数一致"
-------------------------------------------------------------
send buffer = 16384
recv buffer = 87380
--------------------------------------------------------------
"远程测试"
--------------------------------------------------------------
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
void print_buffer(const int &fd) {
    int buffer_size = 0;
    socklen_t opt_len = sizeof(buffer_size);
    if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, &opt_len) == 0) {
        std::cout << "send buffer = " << buffer_size << std::endl;
    }
    if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, &opt_len) == 0) {
        std::cout << "recv buffer = " << buffer_size << std::endl;
    }
}
int main(int argc, char* argv[]) {
    int fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    sockaddr_in socket_address = {};
    socket_address.sin_family = AF_INET;
    socket_address.sin_port   = htons(9501);
    socket_address.sin_addr.s_addr = inet_addr("0.0.0.0");
    if(-1 == ::bind(fd, (sockaddr*)&socket_address, sizeof(sockaddr))) {::close(fd);return -1;}
    if(-1 == ::listen(fd, 123)) { ::close(fd);return -1;}
    sockaddr_in connection_info = {};
    socklen_t sock_addr_len = sizeof(sockaddr_in);
    int client_fd = ::accept(fd, (sockaddr*)&connection_info, &sock_addr_len);
    print_buffer(client_fd);
    ::close(fd);
    ::close(client_fd);
    return 0;
}
"运行结果 与 内核参数不一致 局域网内"
-------------------------------------------------------------
send buffer = 2626560
recv buffer = 1062000
--------------------------------------------------------------

tcp缓冲区的疑惑
-----------------------------------------------------------------------------------------
1."为什么本地与远程的得出的内核发送缓冲是不同的?"
2."远程的这个内核的发送缓冲区的值是如何计算得出的?"
3."按我的理解本地内核的socket缓冲区的参数,只会影响本地的socket,对于远程的socket是无效的?"
-----------------------------------------------------------------------------------------

udp

"在网上查了很多资料,都说这4个参数影响tcp滑动窗口的大小"
sysctl -x net.core.wmem_default 
sysctl -x net.core.rmem_default 
sysctl -x net.core.wmem_max 
sysctl -x net.core.rmem_max
"将它们设置成10W时,我的滑动窗口为28960"
sysctl -x net.core.wmem_default  -> net.core.wmem_default = 100000
sysctl -x net.core.rmem_default  -> net.core.rmem_default = 100000
sysctl -x net.core.wmem_max      -> net.core.wmem_max = 100000
sysctl -x net.core.rmem_max      -> net.core.rmem_max = 100000 

clipboard.png

"将它们设置成8192时,我的滑动窗口还是28960"
sysctl -x net.core.wmem_default  -> net.core.wmem_default = 8192
sysctl -x net.core.rmem_default  -> net.core.rmem_default = 8192
sysctl -x net.core.wmem_max      -> net.core.wmem_max = 8192
sysctl -x net.core.rmem_max      -> net.core.rmem_max = 8192 

clipboard.png

"这四个内核项,没有影响到tcp,反倒是影响了udp的发送缓冲区与接收缓冲区。"
"本地测试"
--------------------------------------------------------------
#include <iostream>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
void print_buffer(const int &fd) {
    int buffer_size = 0;
    socklen_t opt_len = sizeof(buffer_size);
    if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buffer_size, &opt_len) == 0) {
        std::cout << "send buffer = " << buffer_size << std::endl;
    }
    if (getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &buffer_size, &opt_len) == 0) {
        std::cout << "recv buffer = " << buffer_size << std::endl;
    }
}

int main(int argc, char* argv[]) {
    int fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
    print_buffer(fd);
    return 0;
}
"运行结果 与 内核参数一致"
-------------------------------------------------------------
send buffer = 8192
recv buffer = 8192
这4个内核参数的疑惑
-----------------------------------------------------------------------------------------
1."为什么在网上查看的资料都很统一的指向tcp滑动窗口大小?可是我测试的结果却不对呢?"
2."tcp滑动窗口的大小,我方的窗口大小,到底是根据什么参数,来告之对方的呢?"

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

江挽川 2022-09-18 22:18:01

问题里若干不明,只能边猜边答。

tccp :tcp_rmem 跟 tcp_wmem 后面的三个数字是 最小值、默认值、最大值。实际使用的值是动态变化的。你所有看到的结果都在最小值与最大值之间,所以都没有什么问题。

所谓“远程”,你是不是想说一个已经建立连接的 socket?建立连接的时候也是有若干 TCP 包的交换了,buffer 大小在此过程中发生变化也不奇怪。具体逻辑,也许要看代码,或者找其它资料了。

net.core.wmem_default, net.core.rmem_default, net.core.wmem_max, net.core.rmem_max 设置的都是缓冲区的大小。他们适用于所有协议。所以你可以看到 UDP 的缓冲区大小的变化。

而且,由于还有 tcp_wmem 在,在 TCP 里,究竟哪个最大值生效貌似可能于 man page 里写得都不太一样。参见https://stackoverflow.com/q/3...。根据这个问题的答案,tcp_rmem 里的最大值于 rmem_max 里更大的那个生效。于是,rmem_max 对 TCP 基本没有什么作用。rmem_default 自然也会被 tcp_rmem 覆盖掉。(注意 tcp_rmem 同时指定的最小值、默认值、最大值)

TCP 传输过程中,窗口的大小也是可以浮动的。TCP 头里传输的 window size,指这个 package 的发送方,当前还可以接收多少数据(receive window)。这个值当然会随着接受缓存的总大小,以及接受缓存中已经存储的数据量的变化,而不断地发生变化,不会是一个恒定地值。在接收缓冲为空的时候,它通常就是接收缓冲的大小。可能因此才有这些参数可以“控制”窗口大小的说法,因为它们在一定程度上,控制了接收缓冲区的大小。实际情况,可能还要改 tcp_rmem 跟 tcp_wmem 才成。

都是先查的,有错欢迎指出。

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文