cpp-doc-网络基础

PDU

协议数据单元PDU(Protocol Data Unit)是指对等层次之间传递的数据单位。 协议数据单元(Protocol Data Unit )物理层的 PDU是数据位(bit),数据链路层的 PDU是数据帧(frame),网络层的PDU是数据包(packet),传输层的 PDU是数据段(segment),其他更高层次的PDU是报文(message),会话层的PDU是SPDU(section protocol data unit), 表示层的PDU是PPDU(Presentation Protocol Data Unit 表示协议数据单元),应用层的PDU是APDU(application protocol data unit)

OSI/ISO 7层模型(理想模型)

osi(open system interconnection)开放系统互联模型是由ISO(International Organization for Standardization)国际标准化组织定义的网络分层模型,共7层。

OSI/ISO 7层模型图

7层模型详细图
  • 物理层(Physical Layer)
    物理层定义了所有电子及物理设备的规范,为上层的传输提供了一个物理介质,本层中数据传输的单位为比特(bit)。属于本层定义的规范有EIA/TIA RS-232、EIA/TIA RS-449、V35、RJ-45等,实际使用中的设备如网卡等属于本层。
  • 数据链路层(Data Link Layer)
    对物理层收到的比特流进行数据成帧。提供可靠的数据传输服务,实现无差错数据传输。在数据链路层中数据的单位为帧(frame)。属于本层定义的规范有SDLC、HDLC、PPP、STP、帧中继等,实际使用的设备如switch交换机属于本层。
  • 网络层(Network Layer)
    网络层负责将各个子网之间的数据进行路由选择,分组与重组。本层中数据传输的单位为数据包(packet)。属于本层定义的规范有IP、IPX、RIP、OSPF、ICMP、IGMP等。实际使用中的设备如路由器属于本层。
  • 传输层(Transport Layer)
    提供可靠的数据传输服务,它检测路由器丢弃的包,然后产生一个重传请求,能够将乱序收到的数据包重新排序。
  • 会话层(Session Layer)
    管理主机之间会话过程,包括会话建立、终止和会话过程中的管理。
  • 表示层(Presentation Layer)
    表示层对网络传输的数据进行变换,使得多个主机之间传送的信息能够互相理解,包括数据的压缩、加密、格式转换等。
  • 应用层(Application Layer)
    应用层与应用程序界面沟通,以达至展示给用户的目的。在此常见的协议有HTTP、HTTPS、FTP、TELNET、SSH、SMTP、POP3等。

TCP/IP 4层模型(实际模型)

TCP/IP 4层模型图
  • MTU
    (1)以太网和IEEE 802.3对数据帧的长度都有限制,其最大值分别是1500和1492字节(最小值为46,不足46会补全),将这个限制称作为最大传输单元(MTU, Maximum Transmession Unit)。
    (2)如果IP层有一个数据报要传,而且数据的长度比链路层的MTU还大,那么IP层就要进行分片(Fragmentation),把数据报分成若干片,这样每一片都小于MTU。
    (3)当网络上的两台主机互相进行通信时,两台主机之间要经过多个网络,每个网络的链路层可能有不同的MTU,其中两台通信主机路径中的最小MTU被称作路径MTU。
  • 部分协议说明
    ARP:地址解析,将IP地址转成Mac地址。广播ip请求到以太网,符合ip的机器才会响应协议请求。
    RARP:反向地址解析,将MAC地址转成IP地址。

以太网帧格式图

ARP协议解析过程图

网络层(Internet Layer)

  • 部分协议说明
    ICMP:用于传递差错信息、时间、回显、网络信息等控制数据。(例如给一个错误的ip地址发送数据,以太网传输需要目的的mac地址,因为ip无效,icmp就把该错误反馈给源端)

ICMP各种类型

类型 代码 描述
0 0 回显应答(ping)应答
3 目的不可达
0 网络不可达
1 主机不可达
2 协议不可达
3 端口不可达
4 需要进行分片但设置了不分片比特
5 源站选路失败
6 目的网络不认识
7 目的主机不认识
8 源主机被隔离(作废不用)
9 目的网络被强制禁止
10 目的主机被强制禁止
11 由于服务类型TOS,网络不可达
12 由于服务类型TOS,主机不可达
13 由于过滤,通信被强制禁止
14 主机越权
15 优先权中止生效
4 0 源端被关闭(基本流控制)
还很多。。。以后补充

对等通信

在通信过程中,各层经过虚电路只与同样的层通信。

封装(Encapsulation)

在通信的过程中,每一层都加上一个专用的头信息,然后到达对方指定的层时解析指定的头信息,让双方有共同的语言,以达到通信。从应用层到链路层的过程。

TCP 协议头部

tcp协议头图示

源端口号和目的端口号:再加上Ip首部的源IP地址和目的IP地址可以唯一确定一个TCP连接
数据序号:表示在这个报文段中的第一个数据字节序号
确认序号:仅当ACK标志为1时有效。确认号表示期望收到的下一个字节的序号(这个下面再详细分析)
偏移:就是头部长度,有4位,跟IP头部一样,以4字节为单位。最大是60个字节
保留位:6位,必须为0
6个标志位:
URG-紧急指针有效
ACK-确认序号有效
PSH-接收方应尽快将这个报文交给应用层
RST-连接重置
SYN-同步序号用来发起一个连接
FIN-终止一个连接
窗口字段:16位,代表的是窗口的字节容量,也就是TCP的标准窗口最大为2^16 - 1 = 65535个字节
校验和:源机器基于数据内容计算一个数值,收信息机要与源机器数值 结果完全一样,从而证明数据的有效性。检验和覆盖了整个的TCP报文段:这是一个强制性的字段,一定是由发送端计算和存储,并由接收端进行验证的。
紧急指针:是一个正偏移量,与序号字段中的值相加表示紧急数据最后一个字节的序号。TCP的紧急方式是发送端向另一端发送紧急数据的一种方式
选项与填充(必须为4字节整数倍,不够补0):
最常见的可选字段的最长报文大小MSS(Maximum Segment Size),每个连接方通常都在一个报文段中指明这个选项。它指明本端所能接收的最大长度的报文段。
该选项如果不设置,默认为536(20+20+536=576字节的IP数据报)

分用(Demultiplexing)

解封装,在传输过程中,每经过一层去掉对应层的头部信息。从链路层到应用层的过程。

TCP

三次握手

连接3次握手图示
  1. 首先客户端向服务器端发送一段TCP报文,其中:标记位为SYN,表示“请求建立新连接”;序号为Seq=X(X一般为1);随后客户端进入SYN-SENT阶段。

  2. 服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);序号为Seq=y;确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。

  3. 客户端接收到来自服务器端的确认收到数据的TCP报文之后,明确了从客户端到服务器的数据传输是正常的,结束SYN-SENT阶段。并返回最后一段TCP报文。其中:标志位为ACK,表示“确认收到服务器端同意连接的信号”(即告诉服务器,我知道你收到我发的数据了);序号为Seq=x+1,表示收到服务器端的确认号Ack,并将其值作为自己的序号值;确认号为Ack=y+1,表示收到服务器端序号Seq,并将其值加1作为自己的确认号Ack的值;随后客户端进入ESTABLISHED阶段。服务器收到来自客户端的“确认收到服务器数据”的TCP报文之后,明确了从服务器到客户端的数据传输是正常的。结束SYN-SENT阶段,进入ESTABLISHED阶段。

在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性。一旦出现某一方发出的TCP报文丢失,便无法继续”握手”,以此确保了”三次握手”的顺利完成。

四次握手

终止4次握手图示
  1. 客户端发送断开TCP连接请求的报文,其中报文中包含seq序列号,是由发送端随机生成的,并且还将报文中的FIN字段置为1,表示需要断开TCP连接。(FIN=1,seq=x,x由客户端随机生成)

  2. 服务端会回复客户端发送的TCP断开请求报文,其包含seq序列号,是由回复端随机生成的,而且会产生ACK字段,ACK字段数值是在客户端发过来的seq序列号基础上加1进行回复,以便客户端收到信息时,知晓自己的TCP断开请求已经得到验证。(FIN=1,ACK=x+1,seq=y,y由服务端随机生成)

  3. 服务端在回复完客户端的TCP断开请求后,不会马上进行TCP连接的断开,服务端会先确保断开前,所有传输到A的数据是否已经传输完毕,一旦确认传输数据完毕,就会将回复报文的FIN字段置1,并且产生随机seq序列号。(FIN=1,ACK=x+1,seq=z,z由服务端随机生成)

  4. 客户端收到服务端的TCP断开请求后,会回复服务端的断开请求,包含随机生成的seq字段和ACK字段,ACK字段会在服务端的TCP断开请求的seq基础上加1,从而完成服务端请求的验证回复。(FIN=1,ACK=z+1,seq=h,h为客户端随机生成)

至此TCP断开的4次挥手过程完毕。

滑动窗口

维持发送方/接收方缓冲区,缓冲区是用来解决网络之间数据不可靠的问题,例如丢包,重复包,出错,乱序。在TCP协议中,发送方和接受方通过各自维护自己的缓冲区。通过商定包的重传机制等一系列操作,来解决不可靠的问题。

问题一:如果你是TCP设计者,如何保证数据包依次序传输?
解决方案: 发送 <=> 确认机制

单包确认图示

*问题二: *采用问题一的解决方案会带来效率上的弊端,数据包在网络上的传输需要时间解决方案: 一次发送多个包,同时确认多个

多包确认图示

问题三: 我们每次需要发多少个包过去呢?发送多少包是最优解呢?

  • 正常情况
    我们能不能把第一个和第二个包发过去后,收到第一个确认包就把第三个包发过去呢?而不是去等到第二个包的确认包才去发第三个包。这样就很自然的产生了我们”滑动窗口”的实现。

在图中,我们可看出灰色1号2号3号包已经发送完毕,并且已经收到Ack。这些包就已经是过去式。4、5、6、7号包是黄色的,表示已经发送了。但是并没有收到对方的Ack,所以也不知道接收方有没有收到。8、9、10号包是绿色的。是我们还没有发送的。这些绿色也就是我们接下来马上要发送的包。 可以看出我们的窗口正好是7格。后面的11-16还没有被读进内存。要等4号-10号包有接下来的动作后,我们的包才会继续往下发送。

可以看到4号包对方已经被接收到,所以被涂成了灰色。“窗口”就往右移一格,这里只要保证“窗口”是7格的。 我们就把11号包读进了我们的缓存。进入了“待发送”的状态。8、9号包已经变成了黄色,表示已经发送出去了。接下来的操作就是一样的了,确认包后,窗口往后移继续将未发送的包读进缓存,把“待发送“状态的包变为”已发送“。

  • 丢包情况
    有可能我们包发过去,对方的Ack丢了。也有可能我们的包并没有发送过去。从发送方角度看就是我们没有收到Ack。

一般情况:一直在等Ack。如果一直等不到的话,我们也会把读进缓存的待发送的包也一起发过去。但是,这个时候我们的窗口已经发满了。所以并不能把12号包读进来,而是始终在等待5号包的Ack。

如果我们这个Ack始终不来怎么办呢? 采用超时重传机制解决:发送端每发送一个报文段,就启动一个定时器并等待确认信息;接收端成功接收新数据后返回确认信息。若在定时器超时前数据未能被确认,TCP就认为报文段中的数据已丢失或损坏,需要对报文段中的数据重新组织和重传。(重传超时时间: RTO)

分包和粘包

  • TCP分包

场景:发送方发送字符串”helloworld”,接收方却分别接收到了两个数据包:字符串”hello”和”world”;发送端发送了数量较多的数据,接收端读取数据时候数据分批到达,造成一次发送多次读取;

造成分包的原因:TCP是以段(Segment)为单位发送数据的,建立TCP链接后,有一个最大消息长度(MSS).如果应用层数据包超过MSS,就会把应用层数据包拆分,分成两个段来发送。这个时候接收端的应用层就要拼接这两个TCP包,才能正确处理数据。相关的,路由器有一个MTU( 最大传输单元)一般是1500字节,除去IP头部20字节,留给TCP的就只有MTU-20字节。所以一般TCP的MSS为MTU-20=1460字节 当应用层数据超过1460字节时,TCP会分多个数据包来发送。

  • TCP 粘包

场景:发送方发送字符串”helloworld”,接收方却接收到了两个字符串”hello”和”world”。发送端发送了几次数据,接收端一次性读取了所有数据,造成多次发送一次读取;通常是网络流量优化,把多个小的数据段集满达到一定的数据量,从而减少网络链路中的传输次数

TCP粘包的:TCP为了提高网络的利用率,会使用一个叫做Nagle的算法.该算法是指,发送端即使有要发送的数据,如果很少的话,会延迟发送.如果应用层给TCP传送数据很快的话,就会把两个应用层数据包“粘”在一起,TCP最后只发一个TCP数据包给接收端.

分包和粘包解决方案:发送数据前,给数据附加两字节的长度,接收端在收到数据的时候,按发送端明确的长度来读取长度和解析。

tcp11种状态

  1. SYN_SEND
  2. LISTEN
  3. SYN_RCVD
  4. ESTABLISHED
  5. FIN_WAIT_1
  6. CLOSE_WAIT
  7. FIN_WAIT_2
  8. LAST_ACK
  9. TIME_WAIT
  10. CLOSED
  11. CLOSING(双方同时关闭的时候产生)

连接与终止状态图示

UDP

  • 特点
    • 无连接
    • 基于消息的数据传输服务(没粘包问题,数据包之间有边界)
    • 不可靠
    • 一般情况下UDP更加高效
  • 注意点
    • UDP报文可能丢失、重复
    • UDP报文可能会乱序
    • UDP缺乏流量控制
    • UDP协议数据报文截断
    • recvfrom返回0,不代表连接关闭,因为udp是无连接的。
    • ICMP异步错误。
    • UDP connect
    • UDP外出接口的确定

网络字节序

  • 字节序
    • 大端字节序(Big Endian):最高有效位存储最低内存地址处,最低有效位存储于最高内存地址处。
    • 小段字节序(Little Endian):最高有效位存储最高内存地址处,最低有效位存储最低内存地址处。
  • 主机字节序
    不同主机有不同的字节序,如x86位小段字节序,Motorola 6800位打端字节序,ARM字节序是可配置的。
  • 网络字节序
    网络字节序规定为大端字节序。

套接字类型

  • 流式套接字(SOCK_STREAM)
    提供面向连接的、可靠的数据传输服务,数据无差错,无重复的发送,且按发送顺序接收。
  • 数据报式套接字(SOCK_DGRAM)
    提供无连接服务。不提供无错保证,数据可能丢失或重复,并且接收顺序混乱。
  • 原始套接字(SOCK_RAW)

close与shutdown的区别

  • close终止了数据传送的两个方向
    • A方close了,那么A不可以向B发送和接收数据,但B却可以继续向A发数据
    • A会向B发送FIN
  • shutdown可以有选择的终止某个方向的数据传送或者终止数据传送的两个方向。
  • shutdown how=1就可以保证对等方接收到一个EOF字符,而不管其他进程是否已经打开了套接字。而close不能保证,直到套接字引用计数减为0时才发生。也就是说直到所有的进程都关闭了套接字。

数据在网络中传输过程(ping程序)

  1. 应用程序ping会判断发送的是主机还是ip地址,调用函数gethostbyname()解析主机B,将主机名转换成一个32位的IP地址。这个过程叫DNS域名解析。
  2. ping程序向目的IP地址发送一个ICMP的ECHO包。
  3. 将目标主机的ip地址转换位48位硬件地址,在局域网内发送ARP请求广播,查找主机B的硬件地址。
  4. 主机B的ARP协议层接受到主机A的ARP请求后,将本机的硬件地址填充到应答包,发送ARP应答到主机A。
  5. 发送ICMP数据包到主机B。
  6. 主机B接收到主机A的ICMP包,发送响应包。
  7. 主机A接收到主机B的ICMP包响应包。