首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >减少套接字上Linux中的TCP最大分段大小(MSS)

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

Stack Overflow用户
提问于 2013-08-07 23:40:38
回答 2查看 12.4K关注 0票数 1

在我们的服务器需要更新低资源传感器/跟踪设备的固件的特殊应用中,我们遇到了这样的问题:有时在接收新固件的数据包的远程设备(客户端)中数据丢失。该连接是通过GPRS网络的TCP/IP。该装置采用SIM900移动通信芯片作为网络接口。

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

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

在我们的服务器中,我执行了以下操作:

代码语言:javascript
复制
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;
}

运行上面的代码会导致:

代码语言:javascript
复制
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的一些限制,但我没有遇到任何关于这样的行为的报告。

谢谢,丹尼斯

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2013-08-08 06:23:26

但您使用的是u_int16。我没有看到任何说明这个参数不是int的东西。

编辑:是的,here是源代码,你可以看到:

代码语言:javascript
复制
637         if (optlen < sizeof(int))
638                 return -EINVAL;
票数 1
EN

Stack Overflow用户

发布于 2018-03-20 19:04:40

除了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为特定值。

Note1:你在wireshark中看不到这一点,因为wireshark会在这种情况发生之前捕获它。

注2: Iptables不允许增加MSS,只允许降低MSS

我还试着像丹尼斯那样设置套接字选项TCP_MAXSEG。在接受了xaxxon的修复后,这也起到了作用。

注意:您应该在建立连接后读取MSS值。否则,它将返回默认值,这会使我(和dennis)走上错误的轨道。

最后,我还遇到了其他一些事情:

我遇到了TCP-offloading问题,尽管我的

  • 设置正确,但wireshark仍然显示发送的帧太大。您可以通过以下方式禁用此功能:sudo ethtool -K eth0 tx off sg off tso off。我花了很长时间才弄明白这一点。
  • TCP有很多奇特的功能,比如MTU路径发现,它实际上是试图动态增加MSS。有趣和酷,但显然令人困惑。在我的测试

中,我没有遇到任何问题。

希望这能在某一天帮助那些想做同样事情的人。

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18107728

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档