Home 通讯协议
Post
Cancel

通讯协议

HTTP协议

有空补充。

Websocket协议

Websocket协议是应用层协议,它是基于HTTP协议扩展而来,它会保持客户端与服务端的连接,解决了服务端无法主动给客户端发消息的问题。关于weboscket协议,分享一篇好文:websocket协议

Websocket的建立,分两部分:

  • 握手环节
  • 正常通讯环节

握手

Websocket的连接,是在HTTP通讯的基础上升级而来的,这个过程就是握手。

具体流程如下:

  1. 客户端发起一个HTTP请求,在请求头中增加如下信息:

    1
    2
    3
    4
    5
    6
    7
    8
    
    GET /chat HTTP/1.1
    Host: server.example.com
    # 标记升级到websocket协议
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Version: 13
    # 客户端的随机码(base64),后续响应中需要基于该值进行加密
    Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
    
  2. 服务端接收到请求后,发现请求头上的升级信息后,响应http握手信息,并保持tcp连接,转成websocket协议。

    1
    2
    3
    4
    5
    6
    7
    
    # 响应码:101,表示切换协议
    HTTP/1.1 101 Switching Protocols
    Upgrade: websocket
    Connection: Upgrade
    # 基于请求头的随机码,加上固定的字符串:258EAFA5-E914-47DA-95CA-C5AB0DC85B11,做hash计算
    # 主要是为了证明服务器是支持websocket协议的
    Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
    

至此,websocket握手完成,连接成功建立。

通讯

websocket协议定义了自己的通讯帧,定义如下:

ip协议

  • FIN:占1bit,表示是否是消息的最后一个分片。

    如一个文本消息被拆成了3个分片,那3个片的FINopcode分别是:

    • 0,1
    • 0,0
    • 1,0
  • RSV:占3bit,扩展字段,一般是:000。

  • opcode:占4bit,表示有效载荷的类型:

    Opcode含义
    0x0表示一个延续帧,表示本次数据传输采用了数据分片,当前收到的数据帧为其中一个数据分片
    0x1表示这是一个文本帧(frame)
    0x2表示这是一个二进制帧(frame)
    0x3-7保留的操作代码,用于后续定义的非控制帧
    0x8表示连接断开
    0x9表示这是一个ping操作
    0xA表示这是一个pong操作
    0xB-F保留的操作代码,用于后续定义的控制帧
  • MASK:占1bit,掩码标记。若为1,表示启用掩码,数据载荷会使用MASK-KEY加密:

    transform_data[i] = payload[i] XOR MASK_KEY[i%4]

  • Payload len:占7个bit。该部分有三层含义:

    • <= 125时,表示payload长度
    • =126时,表示启用16位的payload扩展,16位扩展会表示实际的payload长度。
    • =127时,表示启用64位的payload扩展,后续64位扩展会表示实际的payload长度。
  • 扩展16位payload len

  • 扩展32 + 16位payload len

  • mask-key:占32位,仅在MASK==1时生效。

粘包与分片

我们在使用websocket时,无需考虑消息的粘包、分片的问题,因为在实现websocket协议的过程中,已经帮我们处理好了。

这里面有个概念需要区分:粘包、分片。

  • 粘包问题。

    • 粘包问题是TCP通讯的问题,一般对裸socket通讯是需要考虑数据的粘包、拆包问题,因为你的协议是自定义的,需要你自己去拆分。
    • 对于websocket来说,它的协议是固定的,在websocket的实现层可以完成粘包、拆包操作。因此不是说websocket没有粘包、拆包问题,而是在实现层已经处理好了,并把完整的消息回调给上层应用。
  • 消息分片。

    这个是websocket协议自己主动将一个消息拆分成多条消息,分片发送。并且,在接受端的websocket实现层中,自动将消息拼装完成后再回调给上层应用。

TCP协议

TCP协议是传输层协议,我们熟知的HTTP协议、DNS协议等都是基于TCP协议(也不准确,也可以基于UDP协议)。

TCP协议的内容有很多,我有时间就补充一点。

协议

ip协议

  • 源端口/目的端口:各占16bit,最大65535分别代表发送端口与接受端口。

  • 序号:代表发送消息的序号,每次发送时,序号会自增1。序号初始值是在TCP握手时随机生成的,并通过SYN包发送给接受端的。

  • 确认号:下一次应该接受到对方消息的序号,仅ACK=1时生效。确认号告诉对方我接受到了你序号是N的消息,你给我发新序号是N+1的消息吧。

  • 数据偏移:占4bit,单位4byte。表示数据开始位置距离首部头位置,即首部长度。

    可以计算下TCP首部的最大长度:15 * 4 = 60byte,以及选项最大长度:60 - 20 = 40byte。

  • URG(urgent):紧急标记,若为1时,表示本消息是紧急消息,需要紧急处理而不是排队。

  • ACK(Acknowledgment):确认标记,仅当值为1时,确认号字段才生效。TCP规定,在连接成功后所有的报文ACK都必须置为1。

  • PSH(Push):

  • RST(Reset):

  • SYN(Synchronization):在连接建立时用来同步序号。SYN=1&ACK=0表示一个连接请求消息,SYN=1&ACK=1表示连接响应消息。

  • FIN(Finish):结束标记,在最后释放连接时使用。

  • 窗口:

  • 校验和:使用CRC算法,计算数据的校验值,数据包括了TCP首部以及数据载荷。接受端使用相同的算法计算出校验值,由此判断数据是否正确。具体流程如下:

    • 发送前,计算校验值:c1 = CRC(data1),并将校验值塞回TCP首部的校验和位置: data2。
    • 接受到数据data2后,先读取并记录下数据的校验和: c2,同时将校验和置为位0: data3。
    • 接着,也计算一遍数据的校验值:c3 = CRC(data3)
    • 比较c2、c3,若不相同代表数据有问题。
  • 紧急指针:

  • 选项:

  • 填充:我的理解是,因为选项长度是不确定的,通过填充补齐首部长度到4的倍数。

握手流程

TCP的3次握手,虽然已经烂大街了,我们还是来回顾一下:

ip协议

至于为啥要设计成3次握手,很多人说:双方都要证明自己有发送、接收数据的能力,我觉得有点牵强。

我理解的根本原因是:如果握手只要两步的话,服务端无法确定接收的连接请求,是有效请求还是由于网络延迟的无效请求。所以,需要客户端增加一步响应,告诉服务端:我还在的,连接请求是有效的。

释放流程

有空补充。

UDP协议

有空补充。

IP协议

IP协议工作在网络层,上层数据帧发送前会经过网络层,此时会在数据帧前添加IP消息头。关于IP协议,分享一篇写得很详细、全面的好文:网络层协议–IP协议.

作为学习笔记,我重复下IP协议的定义:

ip协议

  • 4位版本号(version):指定IP协议的版本(IPv4/IPv6)。

    对于IPv4来说,就是4。

  • 4位首部长度(header length):表示IP报头的长度,以4字节为单位。

    若IP首部没有可选项,那首部的大小为20byte. 由于单位是4byte, 那这里的长度为5(0101)。

    同时,可以计算下IP头以及可选项的最大字节数,首部最大15,即15 * 4 = 60 byte, 可选项最大60 - 20 = 40 byte.

  • 8位服务类型(Type Of Service):3位优先权字段(已经弃用),4位TOS字段,和1位保留字段(必须置为0)。

    4位TOS分别表示:最小延时,最大吞吐量,最高可靠性,最小成本。这四者相互冲突,只能选择一个。比如对于ssh/telnet这样的应用程序,最小延时比较重要,而对于ftp这样的程序,最大吞吐量比较重要。

  • 16位总长度(total length):IP报文(IP报头+有效载荷)的总长度,用于将各个IP报文进行分离。

    长度单位是byte,可以计算下单帧理论上的最大有效载荷,65535 - 20 = 65515 byte。当然这仅是理论值,实际上远远达不到,具体原因看下面的分片部分。

  • 16位标识(id):唯一的标识主机发送的报文,如果数据在IP层进行了分片,那么每一个分片对应的id都是相同的。

  • 3位标志字段:第一位保留,表示暂时没有规定该字段的意义。第二位表示禁止分片,表示如果报文长度超过MTU,IP模块就会丢弃该报文。第三位表示“更多分片”,如果报文没有进行分片,则该字段设置为0,如果报文进行了分片,则除了最后一个分片报文设置为0以外,其余分片报文均设置为1。

    这里涉及到IP分片的问题,根本原因是数据链路层对单帧数据的大小有限制。在数据链路层,MAC帧规定了单帧数据的最大值: 最大传输单元,MTU(Maximum Transmission Unit)。一般MTU的值是1500byte,超过该值的数据会在这里被丢弃,因此在网络层会对大Size的数据进行分片处理,拆成多帧数据给到数据链路层。最后多片数据会在客户端的IP层进行组装,完整后给到上层。

  • 13位片偏移(framegament offset):分片相对于原始数据开始处的偏移,表示当前分片在原数据中的偏移位置,实际偏移的字节数是 ${offset} * 8 byte。因此除了最后一个报文之外,其他报文的长度必须是8的整数倍,否则报文就不连续了。
  • 8位生存时间(Time To Live,TTL):数据报到达目的地的最大报文跳数,一般是64,每经过一个路由,TTL -= 1,一直减到0还没到达,那么就丢弃了,这个字段主要是用来防止出现路由循环。
  • 8位协议:表示上层协议的类型。
  • 16位首部检验和:使用CRC进行校验,来鉴别数据报的首部是否损坏,但不检验数据部分。
  • 32位源IP地址和32位目的IP地址:表示发送端和接收端所对应的IP地址。
  • 可选项:不定长,最多40字节。

ARP协议

有空补充。

IP路由

有空补充。

1
2
3
4
5
6
7
8
9
# 查看arp缓存表
arp -a

# 查看ip路由表
Netstat -r

# 跟踪路由的每一跳
Tracert ip/域名

This post is licensed under CC BY 4.0 by the author.