LWIP_TCP 协议

2024-05-29 16:12
文章标签 协议 tcp lwip

本文主要是介绍LWIP_TCP 协议,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

1 TCP 协议简介

1.1 TCP 协议简介

1.2 TCP 的建立连接

1.3 TCP 终止连接

1.4 TCP 报文结构

 1.5 lwIP 的 TCP 报文首部数据结构

1.6 lwIP 的 TCP 连接状态图

 


1 TCP 协议简介

1.1 TCP 协议简介

        TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

        TCP 为了保证数据包传输的可靠行,会给每个包一个序号,同时此序号也保证了发送到接收端主机能够按序接收。然后接收端主机对成功接收到的数据包发回一个相应的确认字符( ACK, Acknowledgement),如果发送端主机在合理的往返时延( RTT) 内未收到确认字符ACK,那么对应的数据包就被认为丢失并将被重传。 TCP 协议,它是基于连接的一种传输层协议,在发送数据之前要求系统需要在不可靠的信道上建立可靠连接,我们称之为“三次握手”。 建立连接完成之后客户端与服务器才能互发数据, 不需要发送数据时,可以断开连接,这里我们称之为“四次挥手”。

1.2 TCP 的建立连接

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

① TCP 服务器进程先创建传输控制块 TCB,时刻准备接受客户进程的连接请求,此时服务器就进入了 LISTEN(监听)状态。

② TCP 客户进程也是先创建传输控制块 TCB,然后向服务器发出连接请求报文,这是报文首部中的同部位 SYN=1,同时选择一个初始序列号 seq=x ,此时, TCP 客户端进程进入了SYN-SENT(同步已发送状态)状态。 TCP 规定, SYN 报文段(SYN=1 的报文段)不能携带数据,但需要消耗掉一个序号。

③ TCP 服务器收到请求报文后,如果同意连接,则发出确认报文。确认报文中应该ACK=1, SYN=1,确认号是 ack=x+1,同时也要为自己初始化一个序列号 seq=y,此时, TCP服务器进程进入了 SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是同样要消耗一个序号。

④ TCP 客户进程收到确认后,还要向服务器给出确认。确认报文的 ACK=1, ack=y+1,自己的序列号 seq=x+1,此时, TCP 连接建立,客户端进入 ESTABLISHED(已建立连接)状态。 TCP 规定, ACK 报文段可以携带数据,但是如果不携带数据则不消耗序号。

当服务器收到客户端的确认后也进入 ESTABLISHED 状态,此后双方就可以开始通信了。这就是“三次握手”的过程,如下图所示。

1.3 TCP 终止连接

        建立一个连接需要三次握手而终止一个连接需要四次挥手,终止连接有以下过程。

(1) 第一次挥手:客户端发送释放报文,并停止发送数据。释放数据报文首部, FIN=1,其序列号为 seq=u,此时,客户端进入 FIN-WAIT1(等待服务器应答 FIN 报文)。

(2) 第二次挥手:服务器收到客户端的 FIN 报文后,发出确认报文 ACK=1、 ack=u+1,并携带自己的序列号 seq=v。此时,服务器进入 CLOSE-WAIT(关闭等待) 状态。客户端收到服务端确认请求,此时,客户端进入 FIN-WAIT2(终止等待 2)状态,等待服务器发送连接释放报文。

(3) 第三次挥手:服务器向客户端发送连接释放报文 FIN=1、 ack=u+1,此时,服务器进入了 LAST-ACK(最后确认)等待客户端的确认。客户端接收到服务器的连接释放报文后,必须发送确认 ack=1、 ack=w+1,客户端的序列号为 seq=u+1,此时,客户端进入 TIME-WAIT(时间等待)。

(4) 第四次挥手:服务器接收到客户端的确认报文,立刻进入 CLOSED 状态。

这四次挥手就是终止 TCP 协议连接,如下图所示:

1.4 TCP 报文结构

        在传输层中, TCP 的数据包称为数据段, TCP 报文段与 UDP 报文段一样都是封装在 IP 数据报中发送。 TCP 首部包含建立与断开、数据确认、窗口大小通告、数据发送相关的所有标志和控制信息, TCP 报文结构如下图所示:

(1) 源、目标端口号字段:占 16 比特。 TCP 协议通过使用”端口”来标识源端和目标端的应用进程。端口号可以使用 0 到 65535 之间的任何数字。在收到服务请求时,操作系统动态地为客户端的应用程序分配端口号。在服务器端,每种服务在”众所周知的端口”( Well-Know Port)为用户提供服务。

(2) 序列号字段:占 32 比特。用来标识从 TCP 源端向 TCP 目标端发送的数据字节流,它表示在这个报文段中的第一个数据字节。

(3) 确认号字段:占 32 比特。只有 ACK 标志为 1 时,确认号字段才有效。它包含目标端所期望收到源端的下一个数据字节。

(4) 头部长度字段:占 4 比特。给出头部占 32 比特的数目。没有任何选项字段的 TCP 头部长度为 20 字节;最多可以有 60 字节的 TCP 头部。

(5) 标志位字段(U、 A、 P、 R、 S、 F):占 6 比特。各比特的含义如下:

① URG: 紧急指针有效。

② ACK: 为 1 时,确认序号有效。

③ PSH: 为 1 时,接收方应该尽快将这个报文段交给应用层。

④ RST: 为 1 时,重建连接。

⑤ SYN: 为 1 时,同步程序,发起一个连接。

⑥ FIN: 为 1 时,发送端完成任务,释放一个连接。

(6) 窗口大小字段:占 16 比特。此字段用来进行流量控制。单位为字节数,这个值是本机期望一次接收的字节数。

(7) TCP 校验和字段:占 16 比特。对整个 TCP 报文段,即 TCP 头部和 TCP 数据进行校验和计算,并由目标端进行验证。

(8) 紧急指针字段:占 16 比特。它是一个偏移量,和序号字段中的值相加表示紧急数据最后一个字节的序号。

(9) 选项字段:占 32 比特。可能包括”窗口扩大因子”、”时间戳”等选项。

上述的内容讲解的是 TCP 首部信息,这些信息被封装在一个 IP 数据报中, 该数据报结构如下图所示。

 1.5 lwIP 的 TCP 报文首部数据结构

        实现 TCP 协议的文件有 tcp.h、 tcp.c、 tcp_in.c 和 tcp_out.c,这四个文件实现了 TCP 协议全部数据结构和函数, 其中 tcp.c 文件包含了与 TCP 编程、 TCP 定时器相关的函数,而tcp_in.c 文件包含了 TCP 报文段输入处理函数, 而 tcp_out.c 文件包含了 TCP 报文输出处理函数, 当然 tcp.h 定义了宏和结构体。 首先我们看一下 TCP 首部结构,这个结构为 tcp_hdr, 如下源码所示:

struct tcp_hdr {
PACK_STRUCT_FIELD(u16_t src); /* 源端口 */
PACK_STRUCT_FIELD(u16_t dest); /* 目的端口 */
PACK_STRUCT_FIELD(u32_t seqno); /* 序号 */
PACK_STRUCT_FIELD(u32_t ackno); /* 确认序号 */
PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); /* 首部长度+保留位+标志位 */
PACK_STRUCT_FIELD(u16_t wnd); /* 窗口大小 */
PACK_STRUCT_FIELD(u16_t chksum); /* 校验位 */
PACK_STRUCT_FIELD(u16_t urgp); /* 紧急指针 */
} PACK_STRUCT_STRUCT;

        可见, lwIP 使用 tcp_hdr 结构体描述 TCP 首部各个字段,值得注意的是,该结构体的_hdrlen_rsvd_flags 变量用来描述下图黄色部分的内容。

1.6 lwIP 的 TCP 连接状态图

发送端与接收端发送的指令会进入不同的状态, 因此, lwIP 在 tcpbase.h 文件中定义了枚举类型 tcp_state,它是用来描述 TCP 的状态,该枚举tcp_state 如下源码所示:

enum tcp_state {
CLOSED = 0, /* 关闭状态 */
LISTEN = 1, /* 监听状态 */
SYN_SENT = 2, /* 发送请求连接 */
SYN_RCVD = 3, /* 接收请求连接 */
ESTABLISHED = 4, /* 连接状态已建立 */
FIN_WAIT_1 = 5, /* 程序已关闭该连接 */
FIN_WAIT_2 = 6, /* 另一端已关闭连接 */
CLOSE_WAIT = 7, /* 等待程序关闭连接 */
CLOSING = 8, /* 两端同时收到对方的关闭请求 */
LAST_ACK = 9, /* 服务器等待对方接收关闭操作 */
TIME_WAIT = 10 /* 关闭成功 */
}

如果 TCP 需要建立连接,则系统需要三次握手;如果 TCP 中断连接,则系统需要四次挥手。

 

这篇关于LWIP_TCP 协议的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1014009

相关文章

Java如何接收并解析HL7协议数据

《Java如何接收并解析HL7协议数据》文章主要介绍了HL7协议及其在医疗行业中的应用,详细描述了如何配置环境、接收和解析数据,以及与前端进行交互的实现方法,文章还分享了使用7Edit工具进行调试的经... 目录一、前言二、正文1、环境配置2、数据接收:HL7Monitor3、数据解析:HL7Busines

QT实现TCP客户端自动连接

《QT实现TCP客户端自动连接》这篇文章主要为大家详细介绍了QT中一个TCP客户端自动连接的测试模型,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录版本 1:没有取消按钮 测试效果测试代码版本 2:有取消按钮测试效果测试代码版本 1:没有取消按钮 测试效果缺陷:无法手动停

【Linux】应用层http协议

一、HTTP协议 1.1 简要介绍一下HTTP        我们在网络的应用层中可以自己定义协议,但是,已经有大佬定义了一些现成的,非常好用的应用层协议,供我们直接使用,HTTP(超文本传输协议)就是其中之一。        在互联网世界中,HTTP(超文本传输协议)是一个至关重要的协议,他定义了客户端(如浏览器)与服务器之间如何进行通信,以交换或者传输超文本(比如HTML文档)。

【Go】go连接clickhouse使用TCP协议

离开你是傻是对是错 是看破是软弱 这结果是爱是恨或者是什么 如果是种解脱 怎么会还有眷恋在我心窝 那么爱你为什么                      🎵 黄品源/莫文蔚《那么爱你为什么》 package mainimport ("context""fmt""log""time""github.com/ClickHouse/clickhouse-go/v2")func main(

2024.9.8 TCP/IP协议学习笔记

1.所谓的层就是数据交换的深度,电脑点对点就是单层,物理层,加上集线器还是物理层,加上交换机就变成链路层了,有地址表,路由器就到了第三层网络层,每个端口都有一个mac地址 2.A 给 C 发数据包,怎么知道是否要通过路由器转发呢?答案:子网 3.将源 IP 与目的 IP 分别同这个子网掩码进行与运算****,相等则是在一个子网,不相等就是在不同子网 4.A 如何知道,哪个设备是路由器?答案:在 A

图解TCP三次握手|深度解析|为什么是三次

写在前面 这篇文章我们来讲解析 TCP三次握手。 TCP 报文段 传输控制块TCB:存储了每一个连接中的一些重要信息。比如TCP连接表,指向发送和接收缓冲的指针,指向重传队列的指针,当前的发送和接收序列等等。 我们再来看一下TCP报文段的组成结构 TCP 三次握手 过程 假设有一台客户端,B有一台服务器。最初两端的TCP进程都是处于CLOSED关闭状态,客户端A打开链接,服务器端

Modbus-RTU协议

一、协议概述 Modbus-RTU(Remote Terminal Unit)是一种基于主从架构的通信协议,采用二进制数据表示,消息中的每个8位字节含有两个4位十六进制字符。它主要通过RS-485、RS-232、RS-422等物理接口实现数据的传输,传输距离远、抗干扰能力强、通信效率高。 二、报文结构 一个标准的Modbus-RTU报文通常包含以下部分: 地址域:单个字节,表示从站设备

网络原理之TCP协议(万字详解!!!)

目录 前言 TCP协议段格式 TCP协议相关特性 1.确认应答 2.超时重传 3.连接管理(三次握手、四次挥手) 三次握手(建立TCP连接) 四次挥手(断开连接)  4.滑动窗口 5.流量控制 6.拥塞控制 7.延迟应答 8.捎带应答  9.基于字节流 10.异常情况的处理 小结  前言 在前面,我们已经讲解了有关UDP协议的相关知识,但是在传输层,还有

DNS协议基础笔记

1.定义 DNS(Domain Name System,域名系统)是互联网的一项核心服务,它作为将域名和 IP 地址相互映射的一个分布式数据库,能够使人更方便地访问互联网。 2.域名解析过程 当用户在浏览器中输入一个域名,浏览器首先会检查自己的缓存中是否有该域名对应的 IP 地址。本地 DNS 服务器收到查询请求后,首先会检查自己的缓存中是否有该域名对应的 IP 地址。根域名服务器收到查询请

linux下TCP/IP实现简单聊天程序

可以在同一台电脑上运行,在一个终端上运行服务器端,在一个终端上运行客户端。 服务器端的IP地址要和本地的IP相同,并分配端口号,客户端的默认设置为本地,端口号自动分配。 服务器端: #include <stdio.h>#include <stdlib.h>#include <errno.h>#include <string.h>#include <sys/types.