我正在尝试 以编程方式配置 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 是否正确。这是我所看到的:
之后我连接了套接字。
一些注意事项:
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;
}