ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

TCP/IP入门详解--业内最佳

2021-07-22 11:00:12  阅读:91  来源: 互联网

标签:服务器端 -- IP 报文 unsigned TCP 字节 客户端


文章目录

什么是协议

协议实际上就是一种约定。好比说,我们做一个石头剪刀布的游戏,我们约定好:石头>剪刀、剪刀>布、布>石头,以此作为游戏规则。我们所有人都遵循这个约定,那么就不需要任何的多余的沟通便可以完成这个游戏。而这种方式形成的约定实际上就是一种协议了。

什么是协议簇

一组协议的集合/相互关联的一组协议

什么是协议栈

协议的实现和一组协议的关系以及该组协议的层次结构,一般有清晰地up/down依赖关系和上下行交互

OSI模型和TCP/IP模型及对应协议

在这里插入图片描述

OSI七层模型具体作用

物理层:在设备之间传输比特流,规定了电平、速度和电缆针脚。
数据链路层:将比特组合成字节,再将字节组合成帧,使用链路层地址(以太网使用MAC地址)来访问介质,并进行差错检测。
网络层:提供逻辑地址,供路由器确定路径。
传输层:提供面向连接或非面向连接的数据传递以及进行重传前的差错检测。
会话层:负责建立、管理和终止表示层实体之间的通信会话。该层的通信由不同设备中的应用程序之间的服务请求和响应组成。
表示层:提供各种用于应用层数据的编码和转换功能,确保一个系统的应用层发送的数据能被另一个系统的应用层识别。
应用层:OSI参考模型中最靠近用户的一层,为应用程序提供网络服务。

TCP/IP四层模型具体作用

数据链路层:数据链路层实现了网卡接口的网络驱动程序,以处理数据在物理媒介(比如以太网、令牌环等)上的传输。
网络层:网络层实现数据包的选路和转发。
传输层:传输层为两台主机上的应用程序提供端到端(end to end)的通信。与网络层使用的逐跳通信方式不同,传输层只关心通信的起始端和目的端,而不在乎数据包的中转过程。
应用层:应用层负责处理应用程序的逻辑。

数据封装过程

在这里插入图片描述

以太网帧

在这里插入图片描述
目的 MAC 地址:6 个字节,指明帧的接收者。

源 MAC 地址:6 个字节,指明帧的发送者。

类型:2 个字节,指明帧中数据的协议类型,比如常见的 IPv4 中的 ip 协议采用 0x0800。

数据与填充:46~1500 个字节,包含了上层协议传递下来的数据,如果加入数据字段后帧长度不够 64 字节,会在数据字段加入填充字段达到 64 字节。

校验和:4 个字节,对接收网卡(主要是检测数据与填充字段)提供判断是否传输错误的一种方法,如果发现错误,则丢弃此帧。目前最为流行的用于校验和(FCS)的算法是循环冗余校验(cyclic redundancy check – CRC)

IP帧

在这里插入图片描述
IP 协议是 TCP/IP 协议族中最为核心的协议,它提供不可靠的、无连接的服务,也即依赖其他层的协议进行差错控制。在局域网中,IP 协议往往被封装在以太网帧中传送,而所有的 TCP、UDP、ICMP、IGMP 数据都被封装在 IP 数据报中传送。

结构体:

typedef struct _ip_hdr  
{  
    #if LITTLE_ENDIAN  
    unsigned char ihl:4;     //首部长度  
    unsigned char version:4, //版本   
    #else  
    unsigned char version:4, //版本  
    unsigned char ihl:4;     //首部长度  
    #endif  
    unsigned char tos;       //服务类型  
    unsigned short tot_len;  //总长度  
    unsigned short id;       //标志  
    unsigned short frag_off; //分片偏移  
    unsigned char ttl;       //生存时间  
    unsigned char protocol;  //协议  
    unsigned short chk_sum;  //检验和  
    struct in_addr srcaddr;  //源IP地址  
    struct in_addr dstaddr;  //目的IP地址  
}ip_hdr;

版本:4 位,用来表明 IP 协议实现的版本号,当前一般为 IPv4,即 0100,IPv6 的为 0110,这个字段确保可能运行不同 IP 版本的设备之间的兼容性。

首部长度:即报头长度,4 位,以 32 bit 的字来定义 IP 首部的长度,包括可选项。若该字段的最小值是 5 (标准头部长度),即 532=160 比特 =20 字节,此字段最大值为15 (有扩展部分),即1532 =480 比特 = 60 字节。

服务类型:8位,用于携带提供服务质量特征信息的字段,服务类型字段声明了数据报被网络系统传输时可以被怎样处理。其中前 3 比特位优先权子字段(Precedence,现已被忽略,各种终端都不采用)。第 8 比特保留未用。第 4 至第 7 比特分别代表延迟、吞吐量、可靠性和花费,当它们取值为 1 时分别代表要求最小时延、最大吞吐量、最高可靠性和最小花费,这 4 比特的服务类型中只能置其中 1 比特为 1,可以全为 0 ,若全为 0 则表示一般服务,大多数情况下该服务类型会被忽略。

总长度:16 位,指明整个数据报的长度,按字节计算,最大长度为 2^16 字节。

标识:16 位,用来唯一标识主机发送的每一份数据报,IP 软件会在存储器中维持一个计数器,每产生一个数据段,计数器就加 1,并将此值赋给标志字段。但这个“标识”并不是序号,因为 IP 是无连接服务,数据报不存在按序接收问题,如数据报由于超过网络的 MTU (最大传送单元) 而必须分片时,这个标志字段的值就会被复制到所有的数据报的标识字段中,相同的标识字段的值使分片后各数据报片能正确的重装成为原来的数据报。

标志:3 位,分别是 RF、DF、 MF,目前只有 DF,MF 有效,DF(don’t fragment),置为 0 时表示可以分段,置为 1 时是不能被分段,MF(more fragment),置为 0 时表示该数据段为最后一个数据段,置为 1 时表示后面还有被分割分段。

段偏移量:13 位,指出较长的分组在分段后,某段在原分组的相对位置。也就是说相对用户字段的起点,该片从何处开始。段偏移以 8 个字节(有 3 位被 flags 占据)为偏移单位,这就是每个分片的长度一定是 8 字节 (64位) 的整数倍。

生存期:8 位,用来设置数据报最多可以经过的路由器数,由发送数据的源主机设置,通常为 32、64、128等,每经过一个路由器,其值减 1 ,直到 0 该数据报被丢弃。

协议:8 位,指明 ip 数据字段中的数据采用上层什么协议封装的,常见的有 ICMP(1)、IGMP(2)、TCP(6)、UDP(17)

首部校验和:16位,填充根据 ip 头部计算得到的校验和码。计算方法是:对头部中每个 16 比特进行二进制反码求和,但不含涉及头部后的数据字段。

源 IP 地址:源 ip 地址,32 位。

目的 IP 地址:目标 ip 地址,32 位。

选项:n*32 位,用来定义一些可选项:如记录路径、时间戳等,但这些选项很少被使用,同时并不是所有主机和路由器都支持这些选项。可选字段的长度必须是 32 比特的整数倍,如果不足,必须填充 0 以达到此长度要求,根据 IHL(首部长度) 可以得到选项的长度。

数据:不定长度,但受限于数据报的最大长度 2^16 ,这是在数据报中要传输的数据,它是一个完整的较高层报文或报文的一个分片。

TCP 帧

在这里插入图片描述
TCP(Transmission Control Protocol) 即传输控制协议,是一种面向连接的(需通过三次握手来建立 TCP 连接,在主机间建立会话)、可靠的(TCP 通过确认和按顺序传递来确保数据的传递)、基于字节流的传输层通信协议,但 TCP 传输比较慢,开销略高,并且只支持点对点通信。当应用层向 TCP 层发送用于网间传输的 8 字节表示的数据流,TCP 则把数据流分割成适当长度的报文段,最大传输段大小(MSS)通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)限制,之后 TCP 把数据包传给 IP 层,由它来通过网络将包传送给接收端实体的 TCP 层。

结构体:

//TCP头部,总长度20字节  
typedef struct _tcp_hdr  
{  
    unsigned short src_port;    //源端口号  
    unsigned short dst_port;    //目的端口号  
    unsigned int seq_no;        //序列号  
    unsigned int ack_no;        //确认号  
    #if LITTLE_ENDIAN  
    unsigned char reserved_1:4; //保留6位中的4位首部长度  
    unsigned char thl:4;        //tcp头部长度  
    unsigned char flag:6;       //6位标志  
    unsigned char reseverd_2:2; //保留6位中的2位  
    #else  
    unsigned char thl:4;        //tcp头部长度  
    unsigned char reserved_1:4; //保留6位中的4位首部长度  
    unsigned char reseverd_2:2; //保留6位中的2位  
    unsigned char flag:6;       //6位标志   
    #endif  
    unsigned short wnd_size;    //16位窗口大小  
    unsigned short chk_sum;     //16位TCP检验和  
    unsigned short urgt_p;      //16为紧急指针  
}tcp_hdr;  

源端口:2 个字节,是一个大于 1023 的 16 位数字,由基于 TCP 应用程序的用户进程随机选择。

目的端口:2 个字节,指明接收者所用的端口号,一般由应用程序来指定。

顺序号:4 个字节,用来标识从 TCP 源端向 TCP 目的端发送的数据字节流,它表示在这个报文段中的第一个数据字节的顺序号。如果将字节流看作在两个应用程序间的单向流动,则 TCP 用顺序号对每个字节进行计数,序号是 32 bit 的无符号数,序号达到 2^32-1 后又从 0 开始。比如我们收到一个数据报中 sq(顺序号) =0,数据报内容为 20 字节,那么下一个数据报的 sq 就应该是 21。当建立一个新的连接时,SYN 标志变为 1,顺序号字段包含由这个主机选择的该连接的初始顺序号 ISN。

确认序号:4 个字节,包含发送确认的一端所期待收到的下一个顺序号。因此,确认序号应该是上次已经成功收到数据字节顺序号加 1 。比如我们收到的一个数据报的 sq = 0 ,数据报内容为 20 字节,那么我们的 ack(确认序号) 应该是 21 ,用来表明 sq=0 ,内容为 20 字节的数据报已经收到,接下来期望收到的是 sq=21 的数据报。只有 ACK 标志为 1 时确认序号字段才有效。

报文长度:4 位,给出报头中 32 bit 字的数目,需要这个值是因为任选字段的长度是可变的,这个字段占 4 bit,即 TCP 最多有 60 (15*4) 字节的首部。

保留区:6 位,保留给将来使用,目前必须置为 0 。

控制位:6位,控制位包括

URG:为 1 表示紧急指针有效,为 0 则忽略紧急指针值。

ACK:为 1 表示确认号有效,为 0 表示报文中不包含确认信息,忽略确认号字段。

PSH:为 1 表示是带有 PUSH 标志的数据,表示发送端缓存中已经没有待发送的数据,指示接收方应该尽快将这个报文段交给应用层而不用等待缓冲区装满。

RST:用于复位由于主机崩溃或其他原因而出现错误的连接。它还可以用于拒绝非法的报文段和拒绝连接请求。一般情况下,如果收到一个 RST 为 1 的报文,那么一定发生了某些问题。

SYN:同步序号,为 1 表示连接请求,用于建立连接和使顺序号同步。

FIN:用于释放连接,为 1 表示发送方已经没有数据发送了,即关闭本方数据流。

窗口大小:2 个字节,表示从确认号开始,本报文的源方可以接收的字节数,即源方接收窗口的大小。窗口大小是一个 16 bit 字段,因而窗口大小最大为 2^16-1 。

校验和:2 个字节,对整个的 TCP 报文段(包括 TCP 头部和 TCP 数据以及伪报文头)进行校验和计算。这是一个强制性的字段,要求由发送方计算和存储,并由接收端进行验证(接收端要与发送端数值结果完全一样,才能证明数据是有效的)。

紧急指针:2 个字节,是一个正的偏移量,和顺序号字段中的值相加表示紧急数据最后一个字节的序号。TCP 的紧急方式是发送端向另一端发送紧急数据的一种方式,只有当 URG 标志置为 1 时紧急指针才有效。

选项:n*4 字节,常见的可选字段是最长报文大小 MSS(Maximum Segment Size)。每个连接方通常都在通信的第一个报文段 (为建立连接而设置 SYN 标志的那个段) 中指明这个选项,它指明本端所能接收的最大长度的报文段。选项长度不一定是 32 位字的整数倍,所以需要添加填充位,使得报文长度为 32 位字的整数倍。

数据:不定长度,为上层协议封装好的数据。

三次握手

所谓的三次握手即TCP连接的建立。这个连接必须是一方主动打开,另一方被动打开的。以下为客户端主动发起连接的图解:

在这里插入图片描述
握手之前主动打开连接的客户端结束CLOSED阶段,被动打开的服务器端也结束CLOSED阶段,并进入LISTEN阶段。随后开始“三次握手”:

  • 首先客户端向服务器端发送一段TCP报文,其中:
    标记位为SYN,表示“请求建立新连接”;
    序号为Seq=X(X一般为1);
    随后客户端进入SYN-SENT阶段。
  • 服务器端接收到来自客户端的TCP报文之后,结束LISTEN阶段。并返回一段TCP报文,其中:
    标志位为SYN和ACK,表示“确认客户端的报文Seq序号有效,服务器能正常接收客户端发送的数据,并同意创建新连接”(即告诉客户端,服务器收到了你的数据);
    序号为Seq=y;
    确认号为Ack=x+1,表示收到客户端的序号Seq并将其值加1作为自己确认号Ack的值;随后服务器端进入SYN-RCVD阶段。
  • 客户端接收到来自服务器端的确认收到数据的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报文丢失,便无法继续"握手",以此确保了"三次握手"的顺利完成。

此后客户端和服务器端进行正常的数据传输。这就是“三次握手”的过程。

四次挥手

所谓的四次挥手即TCP连接的释放(解除)。连接的释放必须是一方主动释放,另一方被动释放。以下为客户端主动发起释放连接的图解:
在这里插入图片描述
挥手之前主动释放连接的客户端,结束ESTABLISHED阶段。随后开始“四次挥手”:

  • 首先客户端想要释放连接,向服务器端发送一段TCP报文,其中: 标记位为FIN,表示“请求释放连接“; 序号为Seq=U;
    随后客户端进入FIN-WAIT-1阶段,即半关闭阶段。并且停止在客户端到服务器端方向上发送数据,但是客户端仍然能接收从服务器端传输过来的数据。
    注意:这里不发送的是正常连接时传输的数据(非确认报文),而不是一切数据,所以客户端仍然能发送ACK确认报文。

  • 服务器端接收到从客户端发出的TCP报文之后,确认了客户端想要释放连接,随后服务器端结束ESTABLISHED阶段,进入CLOSE-WAIT阶段(半关闭状态)并返回一段TCP报文,其中:
    标记位为ACK,表示“接收到客户端发送的释放连接的请求”; 序号为Seq=V;
    确认号为Ack=U+1,表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值;
    随后服务器端开始准备释放服务器端到客户端方向上的连接。
    客户端收到从服务器端发出的TCP报文之后,确认了服务器收到了客户端发出的释放连接请求,随后客户端结束FIN-WAIT-1阶段,进入FIN-WAIT-2阶段
    前**两次挥手"既让服务器端知道了客户端想要释放连接,也让客户端知道了服务器端了解了自己想要释放连接的请求。**于是,可以确认关闭客户端到服务器端方向上的连接了

  • 服务器端自从发出ACK确认报文之后,经过CLOSED-WAIT阶段,做好了释放服务器端到客户端方向上的连接准备,再次向客户端发出一段TCP报文,其中:
    标记位为FIN,ACK,表示“已经准备好释放连接了”。注意:这里的ACK并不是确认收到服务器端报文的确认报文。 序号为Seq=W;
    确认号为Ack=U+1;表示是在收到客户端报文的基础上,将其序号Seq值加1作为本段报文确认号Ack的值。
    随后服务器端结束CLOSE-WAIT阶段,进入LAST-ACK阶段。并且停止在服务器端到客户端的方向上发送数据,但是服务器端仍然能够接收从客户端传输过来的数据。

  • 客户端收到从服务器端发出的TCP报文,确认了服务器端已做好释放连接的准备,结束FIN-WAIT-2阶段,进入TIME-WAIT阶段,并向服务器端发送一段报文,其中:
    标记位为ACK,表示“接收到服务器准备好释放连接的信号”。
    序号为Seq=U+1;表示是在收到了服务器端报文的基础上,将其确认号Ack值作为本段报文序号的值。
    确认号为Ack=W+1;表示是在收到了服务器端报文的基础上,将其序号Seq值作为本段报文确认号的值。
    随后客户端开始在TIME-WAIT阶段等待2MSL 为什么要客户端要等待2MSL呢?见后文。
    服务器端收到从客户端发出的TCP报文之后结束LAST-ACK阶段,进入CLOSED阶段。由此正式确认关闭服务器端到客户端方向上的连接。
    客户端等待完2MSL之后,结束TIME-WAIT阶段,进入CLOSED阶段,由此完成“四次挥手”。

    后“两次挥手”既让客户端知道了服务器端准备好释放连接了,也让服务器端知道了客户端了解了自己准备好释放连接了。于是,可以确认关闭服务器端到客户端方向上的连接了,由此完成“四次挥手”。
    与“三次挥手”一样,在客户端与服务器端传输的TCP报文中,双方的确认号Ack和序号Seq的值,都是在彼此Ack和Seq值的基础上进行计算的,这样做保证了TCP报文传输的连贯性,一旦出现某一方发出的TCP报文丢失,便无法继续"挥手",以此确保了"四次挥手"的顺利完成。

UDP 帧

在这里插入图片描述
UDP(User Datagram Protocol) 即用户数据报协议,在网络中它与 TCP 协议一样用于处理数据包,是一种不可靠(服务不用确认、不对报文排序、不进行流量控制,可能会出现丢失、重复、失序现象)、无连接(在主机间不建立会话)的协议,在 OSI 模型中的第四层–传输层,处于 IP 协议的上一层。由于 UDP 传输不是可靠性服务,所以帧结构较为简单,而且处理与发送速率高,开销要求低,支持点对点和一点对多点的通信,经常用作音频、视频和普通数据的传输协议,因为它们即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。

结构体:

//UDP头部,总长度8字节  
typedef struct _udp_hdr  
{  
    unsigned short src_port; //远端口号  
    unsigned short dst_port; //目的端口号  
    unsigned short uhl;      //udp头部长度  
    unsigned short chk_sum;  //16位udp检验和  
}udp_hdr;

源端口:16 bit (2 个字节),是一个大于 1023 的 16 位数字,由基于 UDP 应用程序的用户进程随机选择。

目的端口:16 bit (2 个字节),指明接收者所用的端口号,一般由应用程序来指定。

数据长度:16 bit (2 个字节),标明 UDP 头部和 UDP 数据的总字节长度。

校验和字段:16 bit (2 个字节),用来对 UDP 头部和 UDP 数据进行校验。与 TCP 不同的是,此字段是可选项,而 TCP 数据段中必须包含校验和字段。

数据:不定长度,为上层协议封装好的数据。

标签:服务器端,--,IP,报文,unsigned,TCP,字节,客户端
来源: https://blog.csdn.net/weixin_44782055/article/details/118992332

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有