为什么 getsockopt() 没有返回 TCP_MAXSEG 的预期值?

问题描述 投票:0回答:1

我正在尝试 以编程方式配置 GNU/Linux 系统上 TCP 连接的 MSS,特别是 Ubuntu 12.04,内核 3.2.0-68-generic

根据man 7 tcp

TCP_MAXSEG 传出 TCP 数据包的最大分段大小。 如果这 选项在连接建立之前设置,它也会更改 在初始数据包中向另一端公布的MSS值。Values 大于(最终)接口 MTU 没有影响。 TCP 将 还对所提供的值施加其最小和最大界限。

这让我觉得我可以在连接 TCP 套接字之前配置该值。 我编写了一小块代码来创建套接字,并使用 setsockopt() 来配置 MSS。 在我的测试中,我将 mss 设置为 1000B。

代码调用setsockopt(),然后调用getsockopt()来仔细检查值是否已正确配置。两个系统调用都返回 0(无错误)。之后,我连接到远程主机以通过 tcpdump 验证使用的 mss 是否正确。这是我所看到的:

    从 getsockopt() 返回的 MSS 值始终为 536 字节
  • tcpdump 显示 syn 数据包中配置的 MSS
修改了我的代码以配置 MSS

之后我连接了套接字。

    从 getsockopt() 返回的 MSS 值为 1448 Bye
有正确的方法来解释这种行为吗?

一些注意事项:

    根据维基百科 536 B = MaxIPDatagramSize - IPHeaderSize - TcpHeaderSize 这是为了避免 IP 数据包碎片。
  • 创建套接字并连接它(没有调用 setsockopt()),显示 getsockopt() 返回的 mss 为 536 B,但 tcpdump 显示 SYN 数据包中公布的 mss 为 1460 B,有意义的是 1500 - IpHeader - TcpHeader
如果您有兴趣,下面是我的代码:

int setSocketMss( int i_sd, int i_mss ) { int res = 0; int mss = i_mss; socklen_t len = sizeof( mss ); res = ::setsockopt( i_sd, IPPROTO_TCP, TCP_MAXSEG, &mss, len ); if ( res < 0 ) { qDebug() << "error: cannot configure mss for socket" << i_sd; return -1; } res = ::getsockopt( i_sd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len ); if ( mss != i_mss ) { qDebug() << "MSS set to" << i_mss << "but read value is" << mss; } else { qDebug() << "MSS for socket" << i_sd << " has been set to" << mss; } return mss; } void configureAddrStruct( const QString & i_ipAddress, quint16 i_port, struct sockaddr_in & o_sockaddr ) { o_sockaddr.sin_addr.s_addr = htonl( QHostAddress(i_ipAddress).toIPv4Address() ); o_sockaddr.sin_port = htons( i_port ); o_sockaddr.sin_family = PF_INET; memset( o_sockaddr.sin_zero, 0, sizeof(o_sockaddr.sin_zero) ); } int main(int argc, char *argv[]) { int sd = ::socket( PF_INET, SOCK_STREAM, getprotobyname("tcp")->p_proto ); if ( -1 == sd ) { qDebug() << "erro creating socket"; exit (1); } else { qDebug() << "created socket:" << sd; } setSocketMss( sd, 1000 ); struct sockaddr_in localAddress; struct sockaddr_in remoteAddress; configureAddrStruct( "192.168.23.7", 0, localAddress ); configureAddrStruct( "192.168.23.176", 9999, remoteAddress ); int res = ::bind( sd, reinterpret_cast<const sockaddr *>( &localAddress ), sizeof(localAddress) ); if ( -1 == res ) { qDebug() << "error binding socket to local address"; exit(2); } //setSocketMss( sd, 1000 ); res = ::connect( sd, reinterpret_cast<const sockaddr*>( &remoteAddress ), sizeof(remoteAddress) ); if ( -1 == res ) { qDebug() << "error connecting to remote host"; ::perror( "connect()" ); exit(2); } //setSocketMss( sd, 1000 ); return 0; }
    
c linux sockets tcp network-programming
1个回答
-1
投票
你做错了事。您应该在接收器处设置套接字接收缓冲区大小。

© www.soinside.com 2019 - 2024. All rights reserved.