linux 中 tcp 的真正最大段大小是多少?
What is the true maximum segment size of tcp in linux?
我可以从 getsockopt
:
获得 mss 值
tcpmss.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
int main()
{
int sockfd, mss;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("sockfd");
return 1;
}
socklen_t len = sizeof(mss);
if (getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len) < 0)
{
perror("getsockopt");
return 1;
}
printf("maximum segment size: %d\n", mss);
}
输出:
maximum segment size: 536
其他消息来源说,默认的 mss 是 1460
。但是如果我尝试从客户端检查它:
client.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#define GET_CMD "GET %s HTTP/1.0\r\n\r\n"
#define SERV "80"
#define HOST "google.com"
#define HOMEPG "/"
//BUFSIZ = 8192, defined in <stdio.h>
int main()
{
int sockfd, nbytes;
struct addrinfo hints, *res;
char buf[BUFSIZ];
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(HOST, SERV, &hints, &res) != 0)
{
perror("getaddrinfo");
return 1;
}
if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
{
perror("socket");
return 1;
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0)
{
perror("connect");
return 1;
}
nbytes = snprintf(buf, 256, GET_CMD, HOMEPG);
if (write(sockfd, buf, nbytes) < 0)
{
perror("write");
return 1;
}
while ((nbytes = read(sockfd, buf, BUFSIZ)) > 0)
{
printf("read %d bytes of home page of %s\n", nbytes, HOST);
}
if (nbytes == 0)
{
printf("got EOF from google.com");
}
}
输出:
read 8192 bytes of home page of google.com
read 3888 bytes of home page of google.com
read 7248 bytes of home page of google.com
read 4832 bytes of home page of google.com
read 6040 bytes of home page of google.com
read 6040 bytes of home page of google.com
read 6040 bytes of home page of google.com
read 4832 bytes of home page of google.com
read 2229 bytes of home page of google.com
got EOF from google.com
这些值都不正确。所以我对最大段大小有点困惑。我知道 read()
块并将更多 tcp
段提取到内核接收缓冲区中,因此我无法从 read()
系统调用中看到真实的段大小,但是,如何确定约定的 window
在应对应于 MSS 的对等体之间。在第一个 read()
处,我得到了完整的缓冲区,(BUFSIZE == 8192),然后甚至没有一半,等等
如何判断(都来自我的例子)
- MSS
- 在对等点之间传播 window(及其与 MSS 的关系)
- 每次发送操作之间有多少段大小变化(以及为什么)
这是一个比较大的问题,因为它包含了很多东西。
在深入回答之前,我认为最重要的是要了解网络是一条复杂而漫长的道路。我们将路径分为几层,每一层可能有不同的协议,这使事情变得更加复杂。因此,当您发现有关 TCP 的有趣内容时,有时我们还需要查看 lower/upper 层以查看整个路径。
首先,我们总是使用tcpdump和wireshark来分析网络以获取更多细节,这可以帮助您深入了解网络。
至于MSS, it is means Max Segment Size for TCP layer, since we use aonther limitation named as the maximum transmission unit (MTU)这是在单个网络层事务中可以通信的最大协议数据单元(PDU)的大小,MSS总是需要减少一些头部的长度。
至于windowsTCP协议,这里有很多不同的因素我们必须考虑。我们使用window是因为TCP需要ACK来实现可靠传输,send/recvwindow可以检查(也有一些其他原因)。但是随着网络流量的爆炸,TCP增加了拥塞控制,所以window也必须按拥塞window编辑。 MSS/MTU 用作计算默认值的因素,但在此之后,许多 protocols/algorithms 共同努力使 window 改变 TCP 连接的可靠和高效工作。
对于大数据包,TCP 可以在接收时将它们拆分然后组合在一起。更重要的是,硬件也可以做到。这里有TSO(TCP Segmentation Offload)、UFO(UDP Fragmentation Offload)、GSO(Generic Segmentation Offload)、LRO(Large Receive Offload)和GRO(Generic Receive Offload)等技术。
所以你看,这真的很有趣也很复杂。
我可以从 getsockopt
:
tcpmss.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
int main()
{
int sockfd, mss;
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
perror("sockfd");
return 1;
}
socklen_t len = sizeof(mss);
if (getsockopt(sockfd, IPPROTO_TCP, TCP_MAXSEG, &mss, &len) < 0)
{
perror("getsockopt");
return 1;
}
printf("maximum segment size: %d\n", mss);
}
输出:
maximum segment size: 536
其他消息来源说,默认的 mss 是 1460
。但是如果我尝试从客户端检查它:
client.c:
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#define GET_CMD "GET %s HTTP/1.0\r\n\r\n"
#define SERV "80"
#define HOST "google.com"
#define HOMEPG "/"
//BUFSIZ = 8192, defined in <stdio.h>
int main()
{
int sockfd, nbytes;
struct addrinfo hints, *res;
char buf[BUFSIZ];
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if (getaddrinfo(HOST, SERV, &hints, &res) != 0)
{
perror("getaddrinfo");
return 1;
}
if ((sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0)
{
perror("socket");
return 1;
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) < 0)
{
perror("connect");
return 1;
}
nbytes = snprintf(buf, 256, GET_CMD, HOMEPG);
if (write(sockfd, buf, nbytes) < 0)
{
perror("write");
return 1;
}
while ((nbytes = read(sockfd, buf, BUFSIZ)) > 0)
{
printf("read %d bytes of home page of %s\n", nbytes, HOST);
}
if (nbytes == 0)
{
printf("got EOF from google.com");
}
}
输出:
read 8192 bytes of home page of google.com
read 3888 bytes of home page of google.com
read 7248 bytes of home page of google.com
read 4832 bytes of home page of google.com
read 6040 bytes of home page of google.com
read 6040 bytes of home page of google.com
read 6040 bytes of home page of google.com
read 4832 bytes of home page of google.com
read 2229 bytes of home page of google.com
got EOF from google.com
这些值都不正确。所以我对最大段大小有点困惑。我知道 read()
块并将更多 tcp
段提取到内核接收缓冲区中,因此我无法从 read()
系统调用中看到真实的段大小,但是,如何确定约定的 window
在应对应于 MSS 的对等体之间。在第一个 read()
处,我得到了完整的缓冲区,(BUFSIZE == 8192),然后甚至没有一半,等等
如何判断(都来自我的例子)
- MSS
- 在对等点之间传播 window(及其与 MSS 的关系)
- 每次发送操作之间有多少段大小变化(以及为什么)
这是一个比较大的问题,因为它包含了很多东西。
在深入回答之前,我认为最重要的是要了解网络是一条复杂而漫长的道路。我们将路径分为几层,每一层可能有不同的协议,这使事情变得更加复杂。因此,当您发现有关 TCP 的有趣内容时,有时我们还需要查看 lower/upper 层以查看整个路径。
首先,我们总是使用tcpdump和wireshark来分析网络以获取更多细节,这可以帮助您深入了解网络。
至于MSS, it is means Max Segment Size for TCP layer, since we use aonther limitation named as the maximum transmission unit (MTU)这是在单个网络层事务中可以通信的最大协议数据单元(PDU)的大小,MSS总是需要减少一些头部的长度。
至于windowsTCP协议,这里有很多不同的因素我们必须考虑。我们使用window是因为TCP需要ACK来实现可靠传输,send/recvwindow可以检查(也有一些其他原因)。但是随着网络流量的爆炸,TCP增加了拥塞控制,所以window也必须按拥塞window编辑。 MSS/MTU 用作计算默认值的因素,但在此之后,许多 protocols/algorithms 共同努力使 window 改变 TCP 连接的可靠和高效工作。
对于大数据包,TCP 可以在接收时将它们拆分然后组合在一起。更重要的是,硬件也可以做到。这里有TSO(TCP Segmentation Offload)、UFO(UDP Fragmentation Offload)、GSO(Generic Segmentation Offload)、LRO(Large Receive Offload)和GRO(Generic Receive Offload)等技术。
所以你看,这真的很有趣也很复杂。