增加 Linux 上特定套接字的缓冲区大小

增加 Linux 上特定套接字的缓冲区大小

我正在使用 CentOS7,并且必须增加侦听特定端口的套接字上的发送缓冲区大小 (SO_SNDBUF)。打开该端口的应用程序本身不支持此功能。

我尝试过一些可以增加发送缓冲区大小的方法:

  1. 在操作系统上执行此操作-无法执行,因为此缓冲区大小更改必须仅适用于此连接。
  2. Stunnel – 可以完成这项工作,但是客户端的应用程序本身不支持 SSL。
  3. Socat - 这很有可能实现,但到目前为止我只讲了 1 小时的课,甚至还没有触及表面。

编辑:介绍一下背景。我们有一位来自亚洲的客户试图通过交叉连接连接到我们 Java 应用程序上特定套接字上的端口。客户遇到了延迟,网络工程师将问题缩小到 TCP 缓冲区大小不足(正在交换大数据包)。是否有选项可以仅增加此特定套接字上的 TCP 缓冲区大小,而无需使用 stunnel 或通过 TCP 内核设置增加它?

编辑2:如果我没有涉及与该问题具体相关的内容,请告诉我,因为我对此还很陌生。

谢谢大家!

答案1

您可以尝试应用一个加载器垫片,该垫片会拦截对的调用socket(),并setsockopt()在返回给调用者之前执行更改缓冲区大小的操作。假设它没有设置任何奇怪的拦截,那么您可能将其应用于运行应用程序的 Java 解释器。我在 C 程序上测试了以下 C,它似乎有效。请参阅man ld.so

/*
 * capture calls to a routine and replace with your code
 * gcc -Wall -O2 -fpic -shared -ldl -o shim_socket.so shim_socket.c
 * LD_PRELOAD=./shim_socket.so SO_SNDBUF=5000 ./test
 * after call to socket() do SO_SNDBUF on it before return
 */
#define _GNU_SOURCE /* needed to get RTLD_NEXT defined in dlfcn.h */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/socket.h>

int socket(int domain, int type, int protocol){
    static int (*real_socket)(int domain, int type, int protocol) = NULL;
    static int newsize = 0;
    int sock;

    if (!real_socket) {
        real_socket = dlsym(RTLD_NEXT, "socket");
        char *error = dlerror();
        if (error != NULL) {
            fprintf(stderr, "%s\n", error);
            exit(1);
        }
        char *sndbufsize = getenv("SO_SNDBUF");
        if(sndbufsize!=0){
            char *endptr;
            newsize = (int)strtol(sndbufsize,&endptr,0);
            if(*endptr!='\0'){
                fprintf(stderr, "env SO_SNDBUF=was not int\n");
                exit(2);
            }
        }
    }
    sock = real_socket(domain, type, protocol);
    if(newsize){
        int rc = setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &newsize, sizeof(newsize));
        fprintf(stderr, "socket SO_SNDBUF=%d rc=%d\n", newsize, rc);
    }
    return sock;
}

按照注释所示编译并运行此代码。它会在环境中查找SO_SNDBUF=9999所有调用后要应用的值socket()。您可能希望将其限制为仅一些套接字调用。fprintf()输出仅用于测试,甚至可能不会出现在 java 中。根据需要删除。如果您的应用程序运行其他程序,它们可能会继承LD_PRELOAD

请注意,应用程序实际上可能会继续调用setsockopt()自身,将大小改回较小的值。您应该使用类似 的内容进行检查strace -f -e setsockopt -o outputlog。如果这样做,您可以使用拦截此调用的垫片来代替socket()

此外,最大缓冲区大小全局设置为 中的值/proc/sys/net/core/wmem_max。您可以更改此设置,因为只有需要更多缓冲区空间的进程才会使用它。通常,Linux 内核会自动调节进程所需的缓冲量;设置SO_SNDBUF将禁用此机制。

相关内容