![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU1qVTRPQzV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU1qTTBOeTV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU16a3lPUzV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU16a3pNaTV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5ESTJNaTV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
2. 以太网(RFC 894)帧格式 以太网的帧格式如下所示(该图出自[TCPIP]):图 36.6. 以太网帧格式
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5EZzBOUzV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5EVTBOUzV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
0000: ff ff ff ff ff ff 00 05 5d 61 58 a8 08 06
ARP帧(28字节)
0000: 00 01
0010: 08 00 06 04 00 01 00 05 5d 61 58 a8 c0 a8 00 37
0020: 00 00 00 00 00 00 c0 a8 00 02
填充位(18字节)
0020: 00 77 31 d2 50 10
0030: fd 78 41 d3 00 00 00 00 00 00 00 00 以太网首部:目的主机采用广播地址,源主机的MAC地址是00:05:5d:61:58:a8,上层协议类型0×0806表示ARP。ARP帧:硬件类型0×0001表示以太网,协议类型0×0800表示IP协议,硬件地址(MAC地址)长度为6,协议地址(IP地址)长度为4,op为0×0001表示请求目的主机的MAC地址,源主机MAC地址为00:05:5d:61:58:a8,源主机IP地址为c0 a8 00 37(192.168.0.55),目的主机MAC地址全0待填写,目的主机IP地址为c0 a8 00 02(192.168.0.2)。由于以太网规定最小数据长度为46字节,ARP帧长度只有28字节,因此有18字节填充位,填充位的内容没有定义,与具体实现相关。应答帧如下:以太网首部
0000: 00 05 5d 61 58 a8 00 05 5d a1 b8 40 08 06
ARP帧
0000: 00 01
0010: 08 00 06 04 00 02 00 05 5d a1 b8 40 c0 a8 00 02
0020: 00 05 5d 61 58 a8 c0 a8 00 37
填充位
0020: 00 77 31 d2 50 10
0030: fd 78 41 d3 00 00 00 00 00 00 00 00 以太网首部:目的主机的MAC地址是00:05:5d:61:58:a8,源主机的MAC地址是00:05:5d:a1:b8:40,上层协议类型0×0806表示ARP。ARP帧:硬件类型0×0001表示以太网,协议类型0×0800表示IP协议,硬件地址(MAC地址)长度为6,协议地址(IP地址)长度为4,op为0×0002表示应答,源主机MAC地址为00:05:5d:a1:b8:40,源主机IP地址为c0 a8 00 02(192.168.0.2),目的主机MAC地址为00:05:5d:61:58:a8,目的主机IP地址为c0 a8 00 37(192.168.0.55)。思考题:如果源主机和目的主机不在同一网段,ARP请求的广播帧无法穿过路由器,源主机如何与目的主机通信? 4. IP数据报格式 IP数据报的格式如下(这里只讨论IPv4)(该图出自[TCPIP]):图 36.8. IP数据报格式
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5UWXpOaTV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5UY3lPQzV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
B类 128.0.0.0到191.255.255.255
C类 192.0.0.0到223.255.255.255
D类 224.0.0.0到239.255.255.255
E类 240.0.0.0到247.255.255.255 一个A类网络可容纳的地址数量最大,一个B类网络的地址数量是65536,一个C类网络的地址数量是256。D类地址用作多播地址,E类地址保留未用。随着Internet的飞速发展,这种划分方案的局限性很快显现出来,大多数组织都申请B类网络地址,导致B类地址很快就分配完了,而A类却浪费了大量地址。这种方式对网络的划分是flat的而不是层级结构(hierarchical)的,Internet上的每个路由器都必须掌握所有网络的信息,随着大量C类网络的出现,路由器需要检索的路由表越来越庞大,负担越来越重。针对这种情况提出了新的划分方案,称为CIDR(Classless Interdomain Routing)。网络号和主机号的划分需要用一个额外的子网掩码(subnet mask)来表示,而不能由IP地址本身的数值决定,也就是说,网络号和主机号的划分与这个IP地址是A类、B类还是C类无关,因此称为Classless的。这样,多个子网就可以汇总(summarize)成一个Internet上的网络,例如,有8个站点都申请了C类网络,本来网络号是24位的,但是这8个站点通过同一个ISP(Internet service provider)连到Internet上,它们网络号的高21位是相同的,只有低三位不同,这8个站点就可以汇总,在Internet上只需要一个路由表项,数据包通过Internet上的路由器到达ISP,然后在ISP这边再通过次级的路由器选路到某个站点。下面举两个例子:表 36.1. 划分子网的例子1 IP地址140.252.20.688C FC 14 44子网掩码255.255.255.0FF FF FF 00网络号140.252.20.08C FC 14 00子网地址范围140.252.20.0~140.252.20.255 表 36.2. 划分子网的例子2
IP地址140.252.20.688C FC 14 44子网掩码255.255.255.240FF FF FF F0网络号140.252.20.648C FC 14 40子网地址范围140.252.20.64~140.252.20.79 可见,IP地址与子网掩码做与运算可以得到网络号,主机号从全0到全1就是子网的地址范围。IP地址和子网掩码还有一种更简洁的表示方法,例如140.252.20.68/24,表示IP地址为140.252.20.68,子网掩码的高24位是1,也就是255.255.255.0。如果一个组织内部组建局域网,IP地址只用于局域网内的通信,而不直接连到Internet上,理论上使用任意的IP地址都可以,但是RFC 1918规定了用于组建局域网的私有IP地址,这些地址不会出现在Internet上,如下表所示。10.*,前8位是网络号,共16,777,216个地址172.16.*到172.31.*,前12位是网络号,共1,048,576个地址192.168.*,前16位是网络号,共65,536个地址使用私有IP地址的局域网主机虽然没有Internet的IP地址,但也可以通过代理服务器或NAT(网络地址转换)等技术连到Internet上。除了私有IP地址之外,还有几种特殊的IP地址。127.*的IP地址用于本机环回(loop back)测试,通常是127.0.0.1。loopback是系统中一种特殊的网络设备,如果发送数据包的目的地址是环回地址,或者与本机其它网络设备的IP地址相同,则数据包不会发送到网络介质上,而是通过环回设备再发回给上层协议和应用程序,主要用于测试。如下图所示(该图出自[TCPIP])。图 36.10. loopback设备
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5UVTROQzV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
eth0 Link encap:Ethernet HWaddr 00:0C:29:C2:8D:7E
inet addr:192.168.10.223 Bcast:192.168.10.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:10 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:0 (0.0 b) TX bytes:420 (420.0 b)
Interrupt:10 Base address:0x10a0eth1 Link encap:Ethernet HWaddr 00:0C:29:C2:8D:88
inet addr:192.168.56.136 Bcast:192.168.56.255 Mask:255.255.255.0
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:603 errors:0 dropped:0 overruns:0 frame:0
TX packets:110 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:100
RX bytes:55551 (54.2 Kb) TX bytes:7601 (7.4 Kb)
Interrupt:9 Base address:0x10c0lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
UP LOOPBACK RUNNING MTU:16436 Metric:1
RX packets:37 errors:0 dropped:0 overruns:0 frame:0
TX packets:37 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:0
RX bytes:3020 (2.9 Kb) TX bytes:3020 (2.9 Kb)
$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
192.168.10.0 * 255.255.255.0 U 0 0 0 eth0
192.168.56.0 * 255.255.255.0 U 0 0 0 eth1
127.0.0.0 * 255.0.0.0 U 0 0 0 lo
default 192.168.10.1 0.0.0.0 UG 0 0 0 eth0这台主机有两个网络接口,一个网络接口连到192.168.10.0/24网络,另一个网络接口连到192.168.56.0/24网络。路由表的Destination是目的网络地址,Genmask是子网掩码,Gateway是下一跳地址,Iface是发送接口,Flags中的U标志表示此条目有效(可以禁用某些条目),G标志表示此条目的下一跳地址是某个路由器的地址,没有G标志的条目表示目的网络地址是与本机接口直接相连的网络,不必经路由器转发,因此下一跳地址处记为*号。如果要发送的数据包的目的地址是192.168.56.3,跟第一行的子网掩码做与运算得到192.168.56.0,与第一行的目的网络地址不符,再跟第二行的子网掩码做与运算得到192.168.56.0,正是第二行的目的网络地址,因此从eth1接口发送出去,由于192.168.56.0/24正是与eth1接口直接相连的网络,因此可以直接发到目的主机,不需要经路由器转发。如果要发送的数据包的目的地址是202.10.1.2,跟前三行路由表条目都不匹配,那么就要按缺省路由条目,从eth0接口发出去,首先发往192.168.10.1路由器,再让路由器根据它的路由表决定下一跳地址。 6. UDP段格式 下图是UDP的段格式(该图出自[TCPIP])。图 36.11. UDP段格式
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5qazRPUzV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
0000: 00 05 5d 67 d0 b1 00 05 5d 61 58 a8 08 00
IP首部
0000: 45 00
0010: 00 53 93 25 00 00 80 11 25 ec c0 a8 00 37 c0 a8
0020: 00 01
UDP首部
0020: 05 d4 00 45 00 3f ac 40
TFTP协议
0020: 00 01 ‘c”:”\”q’
0030: ‘w”e”r”q”.”q”w”e’00 ‘n”e”t”a’’s”c”i’
0040: ‘i’00 ‘b”l”k’’s”i”z”e’00 ‘5”1”2′00 ‘t”i’
0050: ‘m”e”o”u”t’00 ‘1”0′00 ‘t’’s”i”z”e’00 ‘0′
0060: 00 以太网首部:源MAC地址是00:05:5d:61:58:a8,目的MAC地址是00:05:5d:67:d0:b1,上层协议类型0×0800表示IP。IP首部:每一个字节0×45包含4位版本号和4位首部长度,版本号为4,即IPv4,首部长度为5,说明IP首部不带有选项字段。服务类型为0,没有使用服务。16位总长度字段(包括IP首部和IP层payload的长度)为0×0053,即83字节,加上以太网首部14字节可知整个帧长度是97字节。IP报标识是0×9325,标志字段和片偏移字段设置为0×0000,就是DF=0允许分片,MF=0此数据报没有更多分片,没有分片偏移。TTL是0×80,也就是128。上层协议0×11表示UDP协议。IP首部校验和为0×25ec,源主机IP是c0 a8 00 37(192.168.0.55),目的主机IP是c0 a8 00 01(192.168.0.1)。UDP首部:源端口号0×05d4(1492)是客户端的端口号,目的端口号0×0045(69)是TFTP服务的well-known端口号。UDP报长度为0×003f,即63字节,包括UDP首部和UDP层payload的长度。UDP首部和UDP层payload的校验和为0xac40。TFTP是基于文本的协议,各字段之间用字节0分隔,开头的00 01表示请求读取一个文件,接下来的各字段是:c:\qwerq.qwe
netascii
blksize 512
timeout 10
tsize 0 一般的网络通信都是像TFTP协议这样,通信的双方分别是客户端和服务器,客户端主动发起请求(上面的例子就是客户端发起的请求帧),而服务器被动地等待、接收和应答请求。客户端的IP地址和端口号唯一标识了该主机上的TFTP客户端进程,服务器的IP地址和端口号唯一标识了该主机上的TFTP服务进程,由于客户端是主动发起请求的一方,它必须知道服务器的IP地址和TFTP服务进程的端口号,所以,一些常见的网络协议有默认的服务器端口,例如HTTP服务默认TCP协议的80端口,FTP服务默认TCP协议的21端口,TFTP服务默认UDP协议的69端口(如上例所示)。在使用客户端程序时,必须指定服务器的主机名或IP地址,如果不明确指定端口号则采用默认端口,请读者查阅ftp、tftp等程序的man page了解如何指定端口号。/etc/services中列出了所有well-known的服务端口和对应的传输层协议,这是由IANA(Internet Assigned Numbers Authority)规定的,其中有些服务既可以用TCP也可以用UDP,为了清晰,IANA规定这样的服务采用相同的TCP或UDP默认端口号,而另外一些TCP和UDP的相同端口号却对应不同的服务。很多服务有well-known的端口号,然而客户端程序的端口号却不必是well-known的,往往是每次运行客户端程序时由系统自动分配一个空闲的端口号,用完就释放掉,称为ephemeral的端口号,想想这是为什么。前面提过,UDP协议不面向连接,也不保证传输的可靠性,例如:发送端的UDP协议层只管把应用层传来的数据封装成段交给IP协议层就算完成任务了,如果因为网络故障该段无法发到对方,UDP协议层也不会给应用层返回任何错误信息。接收端的UDP协议层只管把收到的数据根据端口号交给相应的应用程序就算完成任务了,如果发送端发来多个数据包并且在网络上经过不同的路由,到达接收端时顺序已经错乱了,UDP协议层也不保证按发送时的顺序交给应用层。通常接收端的UDP协议层将收到的数据放在一个固定大小的缓冲区中等待应用程序来提取和处理,如果应用程序提取和处理的速度很慢,而发送端发送的速度很快,就会丢失数据包,UDP协议层并不报告这种错误。因此,使用UDP协议的应用程序必须考虑到这些可能的问题并实现适当的解决方案,例如等待应答、超时重发、为数据包编号、流量控制等。一般使用UDP协议的应用程序实现都比较简单,只是发送一些对可靠性要求不高的消息,而不发送大量的数据。例如,基于UDP的TFTP协议一般只用于传送小文件(所以才叫trivial的ftp),而基于TCP的FTP协议适用于各种文件的传输。下面看TCP协议如何用面向连接的服务来代替应用程序解决传输的可靠性问题。 7. TCP协议 7.1. 段格式 TCP的段格式如下图所示(该图出自[TCPIP])。图 36.12. TCP段格式
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5qazVOaTV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU5qWTBNaTV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)
Trying 192.168.0.200...
telnet: Unable to connect to remote host: Connection refused数据传输的过程:客户端发出段4,包含从序号1001开始的20个字节数据。服务器发出段5,确认序号为1021,对序号为1001-1020的数据表示确认收到,同时请求发送序号1021开始的数据,服务器在应答的同时也向客户端发送从序号8001开始的10个字节数据,这称为piggyback。客户端发出段6,对服务器发来的序号为8001-8010的数据表示确认收到,请求发送序号8011开始的数据。在数据传输过程中,ACK和确认序号是非常重要的,应用程序交给TCP协议发送的数据会暂存在TCP层的发送缓冲区中,发出数据包给对方之后,只有收到对方应答的ACK段才知道该数据包确实发到了对方,可以从发送缓冲区中释放掉了,如果因为网络故障丢失了数据包或者丢失了对方发回的ACK段,经过等待超时后TCP协议自动将发送缓冲区中的数据包重发。这个例子只描述了最简单的一问一答的情景,实际的TCP数据传输过程可以收发很多数据段,虽然典型的情景是客户端主动请求服务器被动应答,但也不是必须如此,事实上TCP协议为应用层提供了全双工(full-duplex)的服务,双方都可以 主动甚至同时给对方发送数据。如果通讯过程只能采用一问一答的方式,收和发两个方向不能同时传输,在同一时间只允许一个方向的数据传输,则称为”’半双工(half-duplex)”’,假设某种面向连接的协议是半双工的,则只需要一套序号就够了,不需要通讯双方各自维护一套序号,想一想为什么。关闭连接的过程:客户端发出段7,FIN位表示关闭连接的请求。服务器发出段8,应答客户端的关闭连接请求。服务器发出段9,其中也包含FIN位,向客户端发送关闭连接请求。客户端发出段10,应答服务器的关闭连接请求。建立连接的过程是三方握手,而关闭连接通常需要4个段,服务器的应答和关闭连接请求通常不合并在一个段中,因为有连接半关闭的情况,这种情况下客户端关闭连接之后就不能再发送数据给服务器了,但是服务器还可以发送数据给客户端,直到服务器也关闭连接为止,稍后会看到这样的例子。 7.3. 流量控制 介绍UDP时我们描述了这样的问题:如果发送端发送的速度较快,接收端接收到数据后处理的速度较慢,而接收缓冲区的大小是固定的,就会丢失数据。TCP协议通过”’滑动窗口(Sliding Window)”’机制解决这一问题。看下图的通讯过程。图 36.14. 滑动窗口
![TCP/IP协议栈与数据包封装 TCP/IP协议栈与数据包封装](https://image.shishitao.com:8440/aHR0cHM6Ly93d3cuaXRkYWFuLmNvbS9nby9hSFIwY0RvdkwzVndMakpqZEc4dVkyOXRMekl3TVRNdk1UQXhNUzh5TURFek1UQXhNVEV4TkRBeU56TTFOeTV3Ym1jPQ%3D%3D.jpg?w=700&webp=1)