我正在使用 CentOS7,并且必须增加侦听特定端口的套接字上的发送缓冲区大小 (SO_SNDBUF)。打开该端口的应用程序本身不支持此功能。
我尝试过一些可以增加发送缓冲区大小的方法:
- 在操作系统上执行此操作-无法执行,因为此缓冲区大小更改必须仅适用于此连接。
- Stunnel – 可以完成这项工作,但是客户端的应用程序本身不支持 SSL。
- 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
将禁用此机制。