C/C++ Linux网络编程13 - 传输层TCP协议详解(面向字节流和有连接)

上篇文章:C/C++ Linux网络编程12 - 传输层UDP协议详解-CSDN博客

代码仓库:橘子真甜 (yzc-YZC) - Gitee.com

TCP是传输层协议,特点是:保证可靠传输,面向字节流,有连接。

目录

一. TCP报头格式

二. TCP 面向字节流

1.1 面向字节流理解

1.2 粘包问题

三. TCP 有连接⭐

3.1 连接准备

3.2 三次握手

3.4 四次挥手

3.3 思考总结⭐⭐

a 如果出现了大量的close_wait状态怎么办?

b 为什么要有time_wait状态?

c time_wait的危害是什么?如何解决?

四. TCP可靠性(下篇文章详解)


一. TCP报头格式

首先我们来了解TCP报头格式

可以看到,TCP报头前20字节(160位)是固定的。如果需要数据和选项,可以增加。

既然这样,TCP报头总长度并不是固定的。如果获取TCP报头的大小呢?

可以看到TCP首部有一个字段4位首部长度,这个就是用于计算的。

TCP首部长度 = 4位首部长 * 4 (字节)。

假如 4位首部长是 1111,那么该TCP首部长是 1111(15) * 4 = 60字节

可以看到,TCP首部最长就是60字节,最短是固定首部长20字节

和UDP一样,TCP报文也是一个结构化数据

二. TCP 面向字节流

1.1 面向字节流理解

TCP是面向字节流的,使用socket构建tcp的套接字时候会创建发送缓冲区和接受缓冲区。我们调用接口 recv/send/read/write时候会先将数据拷贝到对应的接收缓冲区中。

而什么时候发送缓冲区发送数据,发送多少。什么时候接受缓冲区接受数据,接受多少。丢包了怎么办。都由底层自己完成。

而我们的用户只需要向缓冲区拷贝/读取数据即可,还可以支持全双工。

1.2 粘包问题

由于TCP是面向字节流的,所以我们读取数据的时候并不能保证读取的数据是一个完整的报文(有可能多,有可能少)这就是粘包问题。

为了解决这种问题,我们要明确每一个报文的边界。

常用的解决方式如下:

1 通信双方规定一个报文是定长的,每次读取定长的数据

2 通过特殊字符对报文进行划分,比如\r\n

3 报头定义报文的长度,每一次去读取标明的长度数据

三. TCP 有连接⭐

TCP保持连接的目的是为了可靠性做基础。有了连接方便支持可靠性的实现。

3.1 连接准备

TCP的连接不是直接就能连接的,连接前需要做一些准备。

被动接收连接方(一般为服务端):

1首先要socket创建套接字(构建fd和tcp控制块)

2 bind绑定端口(完善tcp控制块)

3 isten创建半连接队列syc_queue和全连接队列 accept_queue 将自己设置为LISTEN状态(只有这个状态才能获取网络的连接)。

我们的listen函数( listen(int fd, int backlog) )的第二个参数就全连接队列的长度

主动连接方(一般为客户端):

1 socket创建套接字(构建fd和tcp控制块)

2 connect 连接远方服务器(一般os会自动帮助我们bind一个端口)。

注意:connect是三次握手的开始

3.2 三次握手

这里假设是:server-client

双方准备好连接后(此时server处于LISTEN状态,client处于close状态)

1 client调用connect开始连接,首先client向server发送一个SYN = x,表明自己想要建立连接。

2 server接收syn后如果判断可以连接就会向client发送 ACK = x + 1(表示同意连接请求) 和 自己的SYN = y(表示确认连接请求)。此时该连接也进入了半连接队列

3 然后client接收到 ACK = x + 1 和 SYN = y 之后,如果确认同意连接就发送一个 ACK = y + 1表示同意确立连接请求。此时连接仍处于半连接队列。

4 当server接收到来自client的ACK = y + 1 之后三次握手就完成了(理论是完成了)。此时连接由半连接队列进入全连接队列。

然后当server调用accpet获取这个连接之后双方就能正常send/recv通信了。

流程如下图:

思考

三次握手中有哪些api调用?

connect发起三次握手,listen为三次握手做准备,accpet最后接收三次握手建立的连接。

Tcp第三次握手之后,如何从半连接队列中拿出匹配的连接放入全连接队列?

服务端通过TCP五元组找到半连接队列放入全连接队列。

3.4 四次挥手

网络编程中:调用close fd,当返回0说明这个连接就断开了。调用close之后,双方是如何处理的呢?其实是通过四次挥手处理的。

1 调用close前,双方处于ESTABLISHED状态

2 主动断开方首先调用close发送fin(表示需要断开连接)并进入fin_wait1状态。

3 被动断开方接收fin后进入close_wait状态并发送一个ack(表示同意你的断开请求)然后等待上层调用close,调用close后发送fin(表示我也要断开连接)进入last_ack状态。

4 主动断开方接收ack之后进入fin_wait2状态等待对方的fin,接收到对方的fin后发送ack(表示我也同意你的断开请求)并进入time_wait状态(表示等待对方接收完毕,超时进入closed状态

5 被动界的收到ack之后进入closed状态。

至此四次挥手就完毕了(一般是主动关闭方超时2MSL进入closed状态结束

流程图如下:

3.3 思考总结⭐⭐

由四次挥手可知:

主动断开方最后进入time_wait状态。被动断开方不调用close会一直处于close_wait状态

a如果出现了大量的close_wait状态怎么办?

这种情况一般是服务器压力过大没时间close或者有bug无法正确close。前者想要解决只能等待压力减轻后更换设备或者更换方案了,后者bug需要修改代码即可。

b为什么要有time_wait状态?

time_wait状态大量出现其实是正常状态作用是:

防止主动断开方的最后一个ack丢包,被动断开方一直超时重传 fin 无法从 last_ack 进入closed。time_wait超时2 MSL(最大报文生存时间)期间可以保证对方接受ack。

防止网络中有延迟数据没有被接收导致的数据错误

ctime_wait的危害是什么?如何解决?

服务器关闭后,由于我们的端口处于time_wait此时重启会bind失败。

这个问题的危害:由于time_wait持续的时间是2 MSL这个期间我们的服务是停止的,这是一个巨大的损失。比如双11,如图淘宝两分钟无法服务会造成巨大的影响。

解决这个问题可以使用setsockopt来设置端口复用

正常来说,一个五元组只能bind一个端口。而使用了setsockopt可以保证多个五元组bind同一个端口并且保证不出错。这样就能保证我们的服务器关闭后可以快速重启。

代码如下:(我截取自己服务器的代码)

void initServer() { // 1.创建套接字,使用tcp协议 _listensockfd = socket(AF_INET, SOCK_STREAM, 0); if (_listensockfd < 0) { LogMessage(FATAL, "creat socket error"); exit(SOCKET_ERR); } LogMessage(NORMAL, "creat listensocket success:%d", _listensockfd); // 1.2 设置地址复用 int opt = 1; setsockopt(_listensockfd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)); // 2.bind绑定自己的网络信息,sockfd与IP和port struct sockaddr_in local; memset(&local, 0, sizeof(local)); local.sin_family = PF_INET; // AF_INET就是PF_INET local.sin_port = htons(_port); local.sin_addr.s_addr = INADDR_ANY; if (bind(_listensockfd, (sockaddr *)&local, sizeof(local)) < 0) { LogMessage(FATAL, "server bind error"); exit(BIND_ERR); } LogMessage(NORMAL, "server bind success"); // 3. tcp需要建立连接! 设置监听状态,获取新连接 if (listen(_listensockfd, gbacklog) == -1) { LogMessage(FATAL, "server listen error"); exit(LISTEN_ERR); } LogMessage(NORMAL, "server listen success"); }

参数说明:

SO_REUSEADDR:允许重用处于 TIME_WAIT 状态的地址,或同一IP的不同服务复用。它解决的是 TIME_WAIT 和地址冲突问题。(如果完全冲突的两个服务都活跃是无法bind的,time_wait状态就是一种不活跃的状态所以可以bind

SO_REUSEPORT:允许多个独立套接字绑定到完全相同的 IP:端口。用于多进程/线程同时监听同一端口,实现高性能。(完全冲突的两个服务都也是可以bind的

四. TCP可靠性(下篇文章详解)

可靠性内容较多,下篇文章详解TCP可靠性包含TCP 报头各个字段作用,确认应答,超时重传,连接管理(本文已有),流量控制,滑动窗口,拥塞控制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1014421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

零基础入门:用bpmn-js画你的第一个流程图

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个交互式bpmn-js新手教程&#xff0c;包含&#xff1a;1&#xff09;嵌入式代码编辑器显示基础配置 2&#xff09;分步指引构建请假审批流程&#xff08;开始事件→员工申请→…

智能问数如何让数据分析效率提升10倍

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个效率对比演示应用&#xff0c;左侧展示传统数据分析流程&#xff1a;手动写SQL、导出数据、用Excel制作图表&#xff1b;右侧展示智能问数流程&#xff1a;直接输入自然语言…

3分钟极速安装!MinGW自动化方案对比

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 请生成一个MinGW安装效率对比工具&#xff0c;功能包括&#xff1a;1. 三种安装方式的时间统计 2. 成功率对比 3. 系统资源占用监测 4. 生成可视化对比图表 5. 自动化测试脚本。要求…

电商订单处理系统:工作流引擎落地实践

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个电商订单处理工作流系统&#xff0c;包含以下节点&#xff1a;1)支付验证 2)库存检查 3)物流分配 4)异常订单人工审核 5)售后流程触发。要求实现自动重试机制、超时处理和S…

Java新手必看:jstat从安装到实战图解指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个交互式jstat学习应用&#xff0c;包含&#xff1a;1) jstat安装配置向导&#xff1b;2) 各参数选项可视化解释&#xff1b;3) 模拟JVM状态供练习监控&#xff1b;4) 常见问…

1小时开发:用Python打造专属批量改名工具

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个基于Python的快速批量改名工具原型。要求提供图形界面&#xff0c;支持&#xff1a;1) 选择文件或文件夹 2) 设置命名规则&#xff08;前缀、后缀、序号、日期等&#xff0…

Gradle插件异常?新手也能轻松搞定

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个面向Gradle新手的交互式学习工具&#xff0c;专门讲解org.gradle.api.internal.plugins.pluginapplicationexception: failed错误的处理。包含&#xff1a;1. 基础概念讲解…

如何用AI自动生成Python爬虫代码?快马平台实战

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 请为我生成一个Python爬虫项目&#xff0c;能够爬取豆瓣电影Top250的数据。要求包含以下功能&#xff1a;1. 使用requests库发送HTTP请求 2. 用BeautifulSoup解析HTML 3. 提取电影名…

AI如何帮你彻底清理Windows Installer残留文件

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个AI驱动的Windows Installer清理工具&#xff0c;能够自动扫描系统&#xff0c;识别残留的安装文件和注册表项&#xff0c;并提供一键清理功能。工具应支持多种AI模型分析文…

AI一键批量修改文件名:告别手动操作烦恼

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个基于AI的批量文件名修改工具&#xff0c;能够自动分析文件内容并智能生成新的文件名。要求支持多种文件类型&#xff08;如文档、图片、视频等&#xff09;&#xff0c;提供…

AI如何助力Kiro下载工具开发?

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个基于AI的Kiro下载工具&#xff0c;具备以下功能&#xff1a;1. 智能解析下载链接&#xff0c;自动识别最佳下载源&#xff1b;2. 动态调整下载速度&#xff0c;根据网络状况…

Spring Boot依赖冲突:新手必看指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个面向初Spring Boot开发者的教程&#xff0c;解释org.springframework.boot:spring-boot-starter-par依赖传输失败的原因和解决方法。使用简单的语言和步骤&#xff0c;避免…

1小时快速搭建Kiro下载工具原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 快速开发一个Kiro下载工具最小可行产品(MVP)&#xff0c;包含核心功能&#xff1a;1. 基础下载功能&#xff1b;2. 简单的进度显示&#xff1b;3. 下载历史记录&#xff1b;4. 基本…

5分钟验证:用Anaconda3快速搭建Python开发原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个最小化Anaconda3快速启动工具&#xff0c;功能包括&#xff1a;1.核心组件选择性安装 2.极简开发环境配置 3.常用开发模板快速生成 4.一键运行验证 5.临时环境管理 6.快速卸…

5分钟搭建status_invalid_image_hash检测原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 构建一个极简图像哈希验证原型&#xff0c;功能&#xff1a;1) 文件选择器上传单张图片 2) 计算并显示哈希值 3) 简单匹配验证 4) 显示验证结果。使用纯前端技术HTML/JS实现&#x…

CSS小白必学:5分钟掌握文本溢出省略技巧

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个面向初学者的CSS教程示例&#xff0c;逐步讲解如何实现文本溢出显示省略号。要求&#xff1a;1. 从最基础的white-space/text-overflow属性讲起 2. 包含可视化示意图 3. 提…

15分钟构建可演示的AI容器化POC

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个端到端的AI演示系统&#xff1a;1) 使用预训练模型容器实现实时图像分类&#xff1b;2) 轻量级Web界面接收用户上传图片&#xff1b;3) 可视化推理结果和性能指标。要求&am…

对比:5种Ubuntu下载方式速度实测

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个Ubuntu下载方式对比工具&#xff0c;功能&#xff1a;1. 同时启动多种下载方式(HTTP/FTP/BT/CDN) 2. 实时监测并记录下载速度 3. 生成可视化对比图表 4. 提供下载策略建议 …

3倍效率提升:AI如何快速解决流操作异常

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 构建一个对比演示项目&#xff1a;1) 左侧展示传统方式调试getInputStream()问题的完整过程&#xff1b;2) 右侧使用AI辅助自动分析问题并生成修复方案&#xff1b;3) 包含常见错误…

3分钟极速配置Git环境:效率提升10倍的技巧

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个极简但高效的Git环境一键配置工具。核心功能&#xff1a;1. 单命令执行完成所有配置 2. 智能检测并跳过已配置项 3. 提供典型配置方案选择&#xff08;开发者/设计师/测试人…