网络编程杂谈之TCP协议
TCP协议属于网络分层中的传输层,传输层作用的就是建立端口与端口的通信,而其下一层网络层的主要作用是建立"主机到主机"的通信,所以在我们日常进行网络编程时只要确定主机和端口,就能实现程序之间的数据交流,在Unix系统中就把主机+端口,叫做"套接字"(socket),所以一般网络编程都是基于对于socket的操作来做的。
TCP协议其实是一个非常复杂的协议,做过网络编程开发的都听过一句话‘’TCP本身是一种可靠的协议”,但正是为了保证可靠性,TCP 内部使用了如各种重传与控制算法,所以 TCP 是一个内部原理复杂,但是使用起来比较简单的这么一个协议。
下面我们对TCP协议进行一个基本的介绍,本文只是站在应用的角度上阐述,相比与真正的深入其中还是比较浅显的。
一、TCP协议格式
首先主要看下TCP协议的头格式
其中各字段的意义如下:
1、TCP源端口(Source Port):16位的源端口其中包含发送方应用程序对应的端口。源端口和源IP地址标示报文发送端的地址。
2、TCP目的端口(Destination port):16位的目的端口域定义传输的目的。这个端口指明报文接收计算机上的应用程序地址接口。
3、包序号(Sequence Number):32位的SN序列号标识了TCP报文中第一个byte在对应方向的传输中对应的字节序号,用来记录网络包顺序,解决传输中的乱序、重复问题,比如发送端发送的一个TCP包净荷(不包含TCP头)为10byte,SN为5,则发送端接着发送的下一个数据包的时候,SN应该设置为5+10=15。通过序列号,TCP接收端可以识别出重复接收到的TCP包,从而丢弃重复包,同时对于乱序数据包也可以依靠系列号进行重排序,进而对高层提供有序的数据流。另外如果接收的包中包含SYN或FIN标志位,逻辑上也占用1个byte,应答号需加1。
4、确认号(Acknowledgement Number):32位的ACK标识了报文发送端期望接收的字节序列,如果设置了ACK控制位,这个值表示一个准备接收的包的序列码,注意是准备接收的包,比如当前接收端接收到一个净荷为10byte的数据包,SN为5,则会回复一个确认收到的数据包,如果这个数据包之前的数据也都已经收到了,这个数据包中的ACK Number则设置为10+5=15,表示之前的数据都已经收到了,准备接受SN=15的数据包。
5、窗口(Advertised-Window):著名的滑动窗口(Sliding Window),用于TCP的流量控制。
6、状态位(TCP-FLAG):包的类型,用于操作TCP的状态机,其8位状态分别表示如下含义
- CWR(Congestion Window Reduce) 0x80:拥塞窗口减少标志set by sender,用来表明它接收到了设置ECE标志的TCP包。并且sender 在收到消息之后已经通过降低发送窗口的大小来降低发送速率。
- ECE(ECN Echo) 0x40:ECN响应标志被用来在TCP3次握手时表明一个TCP端是具备ECN功能的。在数据传输过程中也用来表明接收到的TCP包的IP头部的ECN被设置为11。
- URG(Urgent) 0x20:该标志位表示紧急(The urgent pointer) 标志有效,设置为1时,首部中的紧急指针有效;为0时,紧急指针没有意义。紧急数据不进入接收缓冲区直接交给上层进程处理;
- ACK 0x10:取值1代表Acknowledgment Number字段有效,这是一个确认的TCP包,取值0则不是确认包。后续文章介绍中当ACK标志位有效的时候我们称呼这个包为ACK包,使用大写的ACK称呼。
- PSH(Push) 0x08:该标志置位时,一般是表示发送端缓存中已经没有待发送的数据,接收端不将该数据进行队列处理,而是尽可能快将数据转由应用处理。在处理 telnet 或 rlogin 等交互模式的连接时,该标志总是置位的。如果PSH=1的话,就不用等到整个缓存都填满,直接把缓存区中的所有数据进行交付。
- RST(Reset) 0x04:用于reset相应的TCP连接。通常在发生异常或者错误的时候会触发复位TCP连接。
- SYN 0x02:同步序列编号(Synchronize Sequence Numbers)有效。该标志仅在三次握手建立TCP连接时有效。
- FIN(Finish) 0x01:No more data from sender。当FIN标志有效的时候我们称呼这个包为FIN包。
7、校验位(Checksum):16位TCP头。发送端基于数据内容计算一个数值,接收端要与发送端数值结果完全一样,才能证明数据的有效性。接收端checksum校验失败的时候会直接丢掉这个数据包。CheckSum是根据伪头+TCP头+TCP数据三部分进行计算的。
8、紧急指针(Urgent Pointer):16位,指向后面是优先数据的字节,在URG标志设置了时才有效。如果URG标志没有被设置,紧急域作为填充。
9、选项(Option):长度不定,但长度必须以是32bits的整数倍。常见的选项包括MSS、SACK、Timestamp等等。
二、TCP状态机
关于TCP的状态机理解我们从几张经典的示意图开始
TCP状态转换图
TCP三次握手、四次挥手时序图
基于TCP的网络编程中链接的建立断开、数据发送都是依赖TCP状态转换实现的,例如所谓的建立链接并不是真正的链接,而是一种状态的维持,表面上的链接其实是通讯双方共同维护了一个“链接状态”,而建立链接--数据传输--断开链接的TCP通信过程,也是这些状态转换的过程,这其中状态的转换一部分是收到或发送的某个控制位字段的变化而引起的,如SYN、FIN、ACK等,还有一些是由于应用程序的动作或计时器超时引发的。
了解了以上的内容,下面我们就结合实际报文数据,对TCP链接三次握手,数据传输,断开四次挥手,进行一个简单的跟踪验证;
三、TCP通讯
1、三次握手
建立链接的三次握手的作用主要是初始化Sequence Number 的初始值,同时把这个值通过Synchronize Sequence Numbers(SYN包)告知对端。
通过Wireshark可以捕获到三次握手的报文
握手流程:
- 1、client首先初始化该值,发送一个SYN包给server端,告诉server端一个初始化的SN值
- 2、server收到client发送的数据,回复一包数据,包括ACK确认与SYN, 既要告诉client端收到了数据,同时告知对方SYN值;
- 3、client回复ACK确认包,告知server端收到了数据;
2、数据传输
通过Wireshark,我们可以看下TCP传输中一包数据的组成,对照前面的协议组成,可以看到这里我们发送的是0x11,0x11两个字节的数据
可以看到接收一段回复的确认包里ACK从1变成了3,为保证数据的顺序性与可靠性,TCP是有一整套的机制来控制的,如大家熟悉的滑动窗口、超时重传等;
这里有一个需要注意的细节,这里ACK确认号的真实值其实是从0xffeb49ed 变为 0xffed49ef的,这是由于当某个主机开启一个TCP会话时,他的初始序列号与确认号是随机的,可能是0和4,294,967,295之间的任意值,在Wireshark里显示的都是相对序列号/确认号,而不是实际序列号/确认号,相对序列号/确认号是和TCP会话的初始序列号相关联的。这里Wireshark为方便大家跟踪查看显示的是相对值,因为比起真实序列号/确认号,跟踪更小的相对序列号/确认号会相对容易一些。
3、四次挥手
断开链接的四次挥手的作用主要是回收资源,停止数据传输。由于TCP是全双工的,需要client与server两端分别断开各自的通向对方的通道。
通过Wireshark可以捕获到四次挥手的报文
挥手流程:
- 1、client端发送一个FIN包告诉server服务端已经没有数据要传输了,准备断开链接;
- 2、server端回复一个ACK确认包,也就是告诉cient端,好,我知道你要断开了;
- 3、server端这时要看自己还有没有数据要发送给client,如果没有了,也要发送一个FIN包告诉client端,我也没有数据要传输了,准备断开链接;
- 4、client端回复一个ACK确认包,告诉server端,好的,我知道你要断开了;
四次挥手的流程中,sever端在接收到client端的断开要求后,ACK确认包与FIN包是否可以合并为一个包来发送,也就是四次挥手是否可能变成三次挥手,答案是可能的,但由于TCP是全双工的,server端与client端数据传输的终止在时序上是独立且可能相隔较长时间,那么一般情况下一个完整的断开链接操作都是需要四次挥手来完成的。
到这里针对TCP协议,以及链接->传输->断开链接流程的基本介绍与说明就结束了,后续针对网络编程这一块我会接着写几篇文章,一是对自己工作中涉及到一些网络编程的内容进行梳理与总结,另一方面希望能从下至上的加强自己对网络编程这块认知的深度,也希望对大家能有所帮助,其中如有不足与不正确的地方还望指出与海涵。
网络编程杂谈之TCP协议的更多相关文章
- python 之 网络编程(基于TCP协议的套接字通信操作)
第八章网络编程 8.1 基于TCP协议的套接字通信 服务端套接字函数 s.bind() 绑定(主机,端口号)到套接字 s.listen() 开始TCP监听 s.accept() 被动接受TCP客户的连 ...
- 二、网络编程-socket之TCP协议开发客户端和服务端通信
知识点:之前讲的udp协议传输数据是不安全的,不可靠不稳定的,tcp协议传输数据安全可靠,因为它们的通讯机制是不一样的.udp是用户数据报传输,也就是直接丢一个数据包给另外一个程序,就好比寄信给别人, ...
- 学习笔记——网络编程3(基于TCP协议的网络编程)
TCP协议基础 IP协议是Internet上使用的一个关键协议,它的全称是Internet Protocol,即Internet协议,通常简称IP协议. 使用ServerSocket创建TCP服务 ...
- Java网络编程三--基于TCP协议的网络编程
ServerSocket对象用于监听来自客户端的Socket连接,如果没有连接,它将一直处于等待状体 Socket accept():如果接收到客户端的连接请求,该方法返回一个与客户端对应Socket ...
- python 之网络编程(基于TCP协议Socket通信的粘包问题及解决)
8.4 粘包问题 粘包问题发生的原因: 1.发送端需要等缓冲区满才发送出去,造成粘包(发送数据时间间隔很短,数据了很小,会合到一起,产生粘包),这样接收端,就难于分辨出来了,必须提供科学的拆包机制. ...
- Android网络编程系列 一 TCP/IP协议族
在学习和使用Android网路编程时,我们接触的仅仅是上层协议和接口如Apache的httpclient或者Android自带的httpURlconnection等等.对于这些接口的底层实现我们也有必 ...
- Python网络编程02 /基于TCP、UDP协议的socket简单的通信、字符串转bytes类型
Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes类型 目录 Python网络编程02 /基于TCP.UDP协议的socket简单的通信.字符串转bytes ...
- 网络编程Socket之TCP之close/shutdown具体解释(续)
接着上一篇网络编程Socket之TCP之close/shutdown具体解释 如今我们看看对于不同情况的close的返回情况和可能遇到的一些问题: 1.默认操作的close 说明:我们已经知道writ ...
- TCP/IP网络编程之基于TCP的服务端/客户端(二)
回声客户端问题 上一章TCP/IP网络编程之基于TCP的服务端/客户端(一)中,我们解释了回声客户端所存在的问题,那么单单是客户端的问题,服务端没有任何问题?是的,服务端没有问题,现在先让我们回顾下服 ...
随机推荐
- 使用ScriptX控件进行Web横向打印
一个需求需要采用横向打印,目前采用IE自身的打印功能(WebBrowser.ExecWB控件)很难进行横向设置,默认需要调用document.all.WebBrowser.ExecWB(8,1);打开 ...
- How to get binary string from ArrayBuffer?
https://stackoverflow.com/questions/16363419/how-to-get-binary-string-from-arraybuffer https://stack ...
- 解决vue渲染时闪烁{{}}的问题
原文转自: 点我 Vue页面加载时v-show设置的隐藏元素出现导致页面闪烁问题在写APP社区页面的时候在一些地方用了v-show,在刷新页面的时候就发现即便在逻辑判断为false某些元素不该显示时也 ...
- 数学--数论--HDU 2674 沙雕题
WhereIsHeroFrom: Zty, what are you doing ? Zty: I want to calculate N!.. WhereIsHeroFrom: So easy! H ...
- 2019.06.18训练日记(赞FLS)
之前打了几场比赛,有很多题没做出来,这些题无论是知识点不会,还是说在当时时间和思路的影响下没有做出来,这都应该做出来,至少现在必须做出来,本来打算专心复习,分数高了,好保研,但是想了想如果局限于只把学 ...
- 蓝色展开收缩悬浮QQ客服代码
放在我的博客首页上的的预览图: 在文章区的预览图如下: 代码如下: <div class="scrollsidebar" id="scrollsidebar&quo ...
- search(9)- elastic4s logback-appender
前面写了个cassandra-appender,一个基于cassandra的logback插件.正是cassandra的分布式数据库属性才合适作为akka-cluster-sharding分布式应用的 ...
- FPGA自计数六位共阳极数码管动态显示2(调用task的方法)
`timescale 1ns/1ps module adc_dis( clk , rst_n , sm_seg , sm_bit ); input clk;//50HZ input rst_n; :] ...
- Mysql 常用函数(3)- ifnull 函数
Mysql常用函数的汇总,可看下面系列文章 https://www.cnblogs.com/poloyy/category/1765164.html ifnull 的作用 可以判断某个字段的值是否为 ...
- 编译nginx的时候报错 需要安装PCRE
./configure --prefix=/mynginx/ 本地编译nginx的时候 报错 提示需要安装PCRE 错误信息: ./configure: error: the HTTP rewrite ...