TCP报文
- 端口号
端口号是用来区分操作系统中不同进程的.
- 源端口 : 发送TCP报文的应用程序的端口
- 目的端口 : TCP报文的接收端口
- 序号(Sequence number) : 发送出去字节的最末尾序列号
- 确认序号(Acknowledgement number) : 已经确认接收到的字节的序号
- 数据偏移 : 以4个字节为单位, 数据的偏移位, 占4位, 所以TCP头部最大长度为15 * 32 / 8 = 60字节
- 保留 : 3位 以后使用
- NS—ECN-nonce。关于NS的具体解释
- CWR : 用于拥塞处理。关于CWR的具体解释
- ECE : ECN-Echo有两种意思,取决于SYN标志的值。
- URG : 默认为0, 1表示紧急数据包. 此时紧急指针有效.
- ACK : 为1表示确认序号有效, 除了TCP发起建立的第一条报文, 建立成功之后发送的报文ACK均为1
- PSH : 为1表示是带有PUSH标志的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满
- RST : 为1表示出现严重差错。可能需要重新创建TCP连接。还可以用于拒绝非法的报文段和拒绝连接请求
- SYN : 为1表示这是连接请求或是连接接受请求,用于创建连接和使顺序号同步
- FIN : 为1表示发送方没有数据要传输了,要求释放连接
- 窗口(win) : 表示接下来能接收到的最大字节数, 即接收窗口的大小, 用于流量控制
- 效验和 (Check sum) : 用来检查整个TCP报文段是否在传输过程中错误.
- 紧急指针(Urgent pointer) : 本报文段中紧急数据的最后一个字节的位置.
- 选项字段(Options)
- 数据部分(Data) : 数据部分是可选的. 在第三次握手的报文中是可以携带数据的.车大的知乎回答
TCP的三次握手
在TCP协议中, 在客户端和服务端建立连接之后, 数据以流的方式在连接中传播.
创建连接分为3步, 也被大家称为TCP的三次握手.
在建立连接的阶段也是通过TCP报文进行的, 不过字段的值不同.
- 请求连接 请求端发送请求建立连接, 在该TCP报文中, SYN=1, ACK=0, seq=x
- 接受请求 接收端接受建立连接的请求, 返回接受TCP报文, SYN=1,ACK=1,seq=y,ack=x+1
- 请求端确认连接 请求端确认建立TCP连接, 此时ACK=1, seq=x+1, ack=y+1, 在TCP的第三次握手确认连接中, 已经可以发送数据.
TCP为什么需要三次握手? 两次不行么?
如果TCP进行两次握手, 在请求端第一次发送请求连接, 但是这个请求连接报文超时了, 此时请求端再发发送请求连接的报文, 第二次成功建立连接,而且数据传输完毕, 关闭连接之后, 这时候第一次请求连接的报文到达了接收端, 接收端接受连接请求, 但此时请求端却不会发送任何数据给接收端, 因为客户端完全不知道这个连接的存在, 这时候就会浪费接收端的资源来进行等待超时.
其实站在设计者地角度上进行思考, TCP作为可靠连接, 信道是不可靠, 理论上考虑两边地情况之后, 3次握手才能保证连接通道的畅通.
这里可以思考一下, 两军相隔一个山谷, 协商什么时候开始进攻山谷的问题.
TCP的四次挥手
- 发送请求断开连接的一端, 报文中FIN=1
- 接收端接受请求, 然后通知应用层, 对方要关闭连接, 这时候, 将没发送完的数据发送给对方, 对方也要进行接受
- 数据发送完毕, 被动关闭连接的一方, 发送报文中FIN=1
- 主动断开的一方, 确认收到FIN=1的报文, 发送给对方确认关闭连接, 然后进行2 * MSL(最长报文段寿命)的等待后, 撤销接收窗口, 然后进行关闭状态.
这里只说了FIN字段, 因为其他seq, ack字段是与传输过程中”保持一致的”(不是值是一定的), 如果你对TCP的滑动窗口了解的话, 理解起来的是没问题的.
为什么要等待2 * MSL后, 关闭连接端才进入关闭状态?
如果第四次挥手的报文丢失在了网络中, 那么被关闭连接的一方, 可能在超时之后, 继续发送FIN=1的报文, 来确认关闭, 而等待2 * MSL的时间, 就避免了这种情况.
在说上文的时候, 我并没有说客户端和服务器的概念, 因为双方都可以建立或者中断请求, 而TCP对此是透明的, 所以, 我认为不应该以BS或者CS的模型去说TCP.
PREVIOUS解决github io的sitemap生成问题
NEXT初识Redis