gpt4 book ai didi

linux - 减少 Linux 中套接字上的 TCP 最大段大小 (MSS)

转载 作者:可可西里 更新时间:2023-11-01 02:54:43 24 4
gpt4 key购买 nike

在一个特殊的应用程序中,我们的服务器需要更新低资源传感器/跟踪设备的固件,我们遇到了一个问题,有时数据会在接收新固件数据包的远程设备(客户端)。连接是基于 TCP/IP 的GPRS网络。该设备使用SIM900 GSM芯片作为网络接口(interface)。

出现问题的原因可能是设备接收到太多数据。我们尝试减少很少通过发送包来访问流量,但有时仍然会发生错误。

我们联系了 SIM900 芯片的本地零售商,他们也负责提供技术支持,并可能联系芯片的中国制造商 (simcom)。他们说首先我们应该尝试减少连接的 TCP MSS(最大段大小)。

在我们的服务器中我做了以下事情:

static int
create_master_socket(unsigned short master_port) {

static struct sockaddr_in master_address;
int master_socket = socket(AF_INET,SOCK_STREAM,0);
if(!master_socket) {
perror("socket");
throw runtime_error("Failed to create master socket.");
}

int tr=1;
if(setsockopt(master_socket,SOL_SOCKET,SO_REUSEADDR,&tr,sizeof(int))==-1) {
perror("setsockopt");
throw runtime_error("Failed to set SO_REUSEADDR on master socket");
}

master_address.sin_family = AF_INET;
master_address.sin_addr.s_addr = INADDR_ANY;
master_address.sin_port = htons(master_port);
uint16_t tcp_maxseg;
socklen_t tcp_maxseg_len = sizeof(tcp_maxseg);
if(getsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, &tcp_maxseg_len)) {
log_error << "Failed to get TCP_MAXSEG for master socket. Reason: " << errno;
perror("getsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
tcp_maxseg = 256;
if(setsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, tcp_maxseg_len)) {
log_error << "Failed to set TCP_MAXSEG for master socket. Reason: " << errno;
perror("setsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
if(getsockopt(master_socket, IPPROTO_TCP, TCP_MAXSEG, &tcp_maxseg, &tcp_maxseg_len)) {
log_error << "Failed to get TCP_MAXSEG for master socket. Reason: " << errno;
perror("getsockopt");
} else {
log_info << "TCP_MAXSEG: " << tcp_maxseg;
}
if(bind(master_socket, (struct sockaddr*)&master_address,
sizeof(master_address))) {
perror("bind");
close(master_socket);
throw runtime_error("Failed to bind master_socket to port");

}

return master_socket;
}

运行上面的代码会产生:

I0807 ... main.cpp:267] TCP_MAXSEG: 536
E0807 ... main.cpp:271] Failed to set TCP_MAXSEG for master socket. Reason: 22 setsockopt: Invalid argument
I0807 ... main.cpp:280] TCP_MAXSEG: 536

如您所见,问题在输出的第二行:setsockopt 返回“Invalid argument”。

为什么会这样?我阅读了有关设置 TCP_MAXSEG 的一些限制,但我没有遇到任何关于此类行为的报告。

谢谢,丹尼斯

最佳答案

除了 xaxxon 的回答之外,我只想记录一下我在尝试强制我的 Linux 仅发送特定大小(低于通常大小)的最大 TCP 段方面的经验:

  • 我发现最简单的方法是使用 iptables:

sudo iptables -A INPUT -p tcp --tcp-flags SYN,RST SYN --destination 1.1.1.1 -j TCPMSS --set-mss 200

这会覆盖出站连接上的远程传入 SYN/ACK 数据包,并强制 MSS 为特定值。

注意 1:您在 wireshark 中看不到这一点,因为 wireshark 在发生这种情况之前进行了捕获。

注意 2:Iptables 不允许您“增加”MSS,只能降低它

  • 或者,我也尝试设置套接字选项 TCP_MAXSEG,就像丹尼斯所做的那样。从 xaxxon 获得修复后,这也有效。

注意:您应该在建立连接后读取 MSS 值。否则它会返回默认值,这让我(和丹尼斯)走错了路。

现在终于,我还遇到了一些其他的事情:

  • 我遇到了TCP 卸载 问题,尽管我的 MSS 设置正确,但发送的帧仍然被 wireshark 显示为太大。您可以通过以下方式禁用此功能:sudo ethtool -K eth0 tx off sg off tso off。这花了我很长时间才弄明白。

  • TCP 有很多奇特的东西,比如 MTU 路径发现,它实际上会尝试动态增加 MSS。有趣又酷,但显然令人困惑。虽然在我的测试中我没有遇到问题

希望这有助于有一天尝试做同样事情的人。

关于linux - 减少 Linux 中套接字上的 TCP 最大段大小 (MSS),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18107728/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com