抓包分析MSS/MTU

               MTU为最大传输单元,它的含义实际上就是数据链路对IP包长度要求的最大值,以太网不得超过1500。MSS表示最大段的最大值,它是与TCP相关的一个概念,TCP的传输层是分段的,数据链路层期望的最大IP包长是1500字节,那么除去IP包头典型的20字节,再除去TCP包头典型的20字节(或者其他<=60字节的数据),可知,数据链路允许的最大TCP业务长度是1460字节。所以最大段(MSS)是1460字节。一帧不能超过1518字节,因为帧头占18字节,帧头包括:目的MAC(6)+源MAC(6)+Type(2)+CRC(4)。上述都是针对以太网而言。我下面测试用的是回环地址,它们以太网对应的MTU不一样。

回环地址对应的MTU:

MTU=65536,则MSS=65536-20-20=65492

 

此时回环地址的MSS=65528,当协议为TCP时,一次性发送的数据大于65528,TCP就会对数据进行分段发送。

服务端:

 

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#define MAXLINE 4096



int main()
{
   int listenfd,acceptfd,n;
   socklen_t  clilen;
   char recvbuf[80000]={0};
   struct sockaddr_in cliaddr,servaddr;

   listenfd=socket(AF_INET,SOCK_STREAM,0);
   servaddr.sin_family=AF_INET;
   servaddr.sin_port=htons(8888);
   servaddr.sin_addr.s_addr = INADDR_ANY; 

   bind(listenfd,(struct sockaddr *)&servaddr,sizeof(struct sockaddr_in));
   listen(listenfd,5);

   clilen=sizeof(cliaddr);
   acceptfd=accept(listenfd,(struct sockaddr *)&cliaddr,&clilen);

   recv(acceptfd,recvbuf,sizeof(recvbuf)-1,0);
   printf("recvbuf=%s\n",recvbuf);
   getchar();
   close(acceptfd);
   close(listenfd);
   return 0;
}


客户端:

 

 

#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <malloc.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/ioctl.h>
#include <stdarg.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <signal.h>
#include <netinet/tcp.h>
#define MAXLINE 4096


int main()
{
   int sockfd;
   struct sockaddr_in servaddr;
   char sendbuf[60000]={0};

   sockfd=socket(AF_INET,SOCK_STREAM,0);
   bzero(&servaddr,sizeof(servaddr));
   servaddr.sin_family=AF_INET;
   servaddr.sin_port=htons(8888);
   servaddr.sin_addr.s_addr = inet_addr("127.0.0.1");


   connect(sockfd,(struct sockaddr *)&servaddr,sizeof(servaddr));
   write(sockfd,sendbuf,sizeof(sendbuf)+1);


   getchar();
   getchar();
   close(sockfd);
   return 0;
}

 

 

先启动服务端,再启动客户端,用tcpdump抓包

 

20:13:21.751121 IP 127.0.0.1.48148 > 127.0.0.1.ddi-tcp-1: Flags [S], seq 989177476, win 65495, options [mss 65495,sackOK,TS val 3584598474 ecr 0,nop,wscale 7], length 0
20:13:21.751136 IP 127.0.0.1.ddi-tcp-1 > 127.0.0.1.48148: Flags [S.], seq 3566618469, ack 989177477, win 65483, options [mss 65495,sackOK,TS val 3584598474 ecr 3584598474,nop,wscale 7], length 0
20:13:21.751149 IP 127.0.0.1.48148 > 127.0.0.1.ddi-tcp-1: Flags [.], ack 1, win 512, options [nop,nop,TS val 3584598474 ecr 3584598474], length 0
20:13:21.751210 IP 127.0.0.1.48148 > 127.0.0.1.ddi-tcp-1: Flags [.], seq 1:32742, ack 1, win 512, options [nop,nop,TS val 3584598474 ecr 3584598474], length 32741
20:13:21.751238 IP 127.0.0.1.ddi-tcp-1 > 127.0.0.1.48148: Flags [.], ack 32742, win 1024, options [nop,nop,TS val 3584598474 ecr 3584598474], length 0
20:13:21.751250 IP 127.0.0.1.48148 > 127.0.0.1.ddi-tcp-1: Flags [P.], seq 32742:60002, ack 1, win 512, options [nop,nop,TS val 3584598474 ecr 3584598474], length 27260
20:13:21.790695 IP 127.0.0.1.ddi-tcp-1 > 127.0.0.1.48148: Flags [.], ack 60002, win 862, options [nop,nop,TS val 3584598514 ecr 3584598474], length 0

6000个字节被分成了两个包,32741和27260两个。但是MSS>60000,为什么会被分段发送呢?这只是实现不同而已,在MSS的限制下,协议栈和系统具体进行怎样的限制,并无错误。下面我们将客户端改一下,将发送的6000字节改成32740,在抓包。

 

 

20:30:37.187347 IP 127.0.0.1.48156 > 127.0.0.1.ddi-tcp-1: Flags [S], seq 1517440416, win 65495, options [mss 65495,sackOK,TS val 3585633910 ecr 0,nop,wscale 7], length 0
20:30:37.187364 IP 127.0.0.1.ddi-tcp-1 > 127.0.0.1.48156: Flags [S.], seq 3842770501, ack 1517440417, win 65483, options [mss 65495,sackOK,TS val 3585633910 ecr 3585633910,nop,wscale 7], length 0
20:30:37.187381 IP 127.0.0.1.48156 > 127.0.0.1.ddi-tcp-1: Flags [.], ack 1, win 512, options [nop,nop,TS val 3585633910 ecr 3585633910], length 0
20:30:37.187464 IP 127.0.0.1.48156 > 127.0.0.1.ddi-tcp-1: Flags [P.], seq 1:32742, ack 1, win 512, options [nop,nop,TS val 3585633910 ecr 3585633910], length 32741
20:30:37.187510 IP 127.0.0.1.ddi-tcp-1 > 127.0.0.1.48156: Flags [.], ack 32742, win 1024, options [nop,nop,TS val 3585633910 ecr 3585633910], length 0

看,没有分段了。

 

上面说的TCP,对于UDP,它是没有MSS这个概念的。但是它又最大发包大小,如果UDP发送的数据超过这个最大值,那么数据就会在IP层进行分片。IP包头有个16bit的长度,对于二进制最大值为2^16-1。除去IP包头20字节,UDP包头8字节,为65507。和TCP对比,TCP的MSS为1460,小于65507合理。我们说TCP没有最大发包大小,为啥呢?因为TCP会在传输层分段。对于UDP而言,发送超过65507字节的数据,就会发送失败。

 

参考地址:http://blog.csdn.net/stpeace/article/details/74152332

 

 

 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盼盼编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值