TCP状态转换图

news2024/11/16 20:43:56

TCP状态转换图
在这里插入图片描述

了解TCP状态转换图可以帮助开发人员查找问题.
说明: 上图中粗线表示主动方, 虚线表示被动方, 细线部分表示一些特殊情况, 了解即可, 不必深入研究.
对于建立连接的过程客户端属于主动方, 服务端属于被动接受方(图的上半部分)
而对于关闭(图的下半部分), 服务端和客户端都可以先进行关闭.
处于ESTABLISHED状态的时候就可以收发数据了, 双方在通信过程当中一直处于ESTABLISHED状态, 数据传输期间没有状态的变化.
TIME_WAIT状态一定是出现在主动关闭的一方.
主动关闭的Socket端会进入TIME_WAIT状态,并且持续2MSL时间长度,MSL就是maximum segment lifetime(最大分节生命期),这是一个IP数据包能在互联网上生存的最长时间,超过这个时间将在网络中消失。

使用netstat -anp可以查看连接状态

注:数据传输的时候带了一个字节的数据, 所以server发送给client的ACK=x+2

为什么需要2MSL?
原因之一: 让四次挥手的过程更可靠, 确保最后一个发送给对方的ACK到达;
若对方没有收到ACK应答, 对方会再次发送FIN请求关闭, 此时在2MS时间内被动关闭方仍然可以发送ACK给对方.

原因之二: 为了保证在2MS时间内, 不能启动相同的SOCKET-PAIR.
TIME_WAIT一定是出现在主动关闭的一方, 也就是说2MS是针对主动关 闭一方来说的;由于TCP有可能存在丢包重传, 丢包重传若发给了已经断 开连接之后相同的socket-pair(该连接是新建的, 与原来的socket-pair完 全相同, 双方使用的是相同的IP和端口), 这样会对之后的连接造成困扰, 严重可能引起程序异常.

如何避免问题2呢??
	--很多操作系统实现的时候, 只要端口被占用, 服务就不能启动.

测试: 启动服务端和客户端, 然后先关闭服务端, 再次启动服务端, 此时服务端报错: bind error: Address already in use; 若是先关闭的客户端, 再关闭的服务端, 此时启动服务端就不会报这个错误.

socket-pair的概念: 客户端与服务端连接其实是一个连接对, 可以通过使用netstat -anp | grep 端口号 进行查看.

端口复用
解决端口复用的问题: bind error: Address already in use, 发生这种情况是在服务端主动关闭连接以后, 接着立刻启动就会报这种错误.

setsockopt函数
int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t optlen);
setsockopt(lfd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(int));
setsockopt(lfd, SOL_SOCKET, SO_REUSEPORT, &opt, sizeof(int));
函数说明可参看<<UNIX环境高级编程>>
由于错误是bind函数报出来的, 该函数调用要放在bind之前, socket之后调用.

半关闭状态
半关闭的概念:
如果一方close, 另一方没有close, 则认为是半关闭状态, 处于半关闭状态的 时候, 可以接收数据, 但是不能发送数据. 相当于把文件描述符的写缓冲区 操作关闭了.
注意: 半关闭一定是出现在主动关闭的一方.

shutdown函数
长连接和端连接的概念:
连接建立之后一直不关闭为长连接;
连接收发数据完毕之后就关闭为短连接;

shutdown和close的区别:
shutdown能够把文件描述符上的读或者写操作关闭, 而close关闭文件描述 符只是将连接的引用计数的值减1, 当减到0就真正关闭文件描述符了.
如: 调用dup函数或者dup2函数可以复制一个文件描述符, close其中一个并 不影响另一个文件描述符, 而shutdown就不同了, 一旦shutdown了其中一 个文件描述符, 对所有的文件描述符都有影响 .

心跳包
如何检查与对方的网络连接是否正常??
一般心跳包用于长连接.
方法1
keepAlive = 1;
setsockopt(listenfd, SOL_SOCKET, SO_KEEPALIVE, (void*)&keepAlive, sizeof(keepAlive));
由于不能实时的检测网络情况, 一般不用这种方法
方法2: 在应用程序中自己定义心跳包, 使用灵活, 能实时把控.

到此为止, 概念相关的东西就讲完毕了.

高并发服务器模型–select

继续研究高并发服务器的问题.
多路IO技术: select, 同时监听多个文件描述符, 将监控的操作交给内核去处理,

数据类型fd_set: 文件描述符集合–本质是位图(关于集合可联想一个信号集sigset_t)
int select(int nfds, fd_set * readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
函数介绍: 委托内核监控该文件描述符对应的读,写或者错误事件的发生.
参数说明:
nfds: 最大的文件描述符+1
readfds: 读集合, 是一个传入传出参数
传入: 指的是告诉内核哪些文件描述符需要监控
传出: 指的是内核告诉应用程序哪些文件描述符发生了变化
writefds: 写文件描述符集合(传入传出参数)
execptfds: 异常文件描述符集合(传入传出参数)
timeout:
NULL–表示永久阻塞, 直到有事件发生
0 --表示不阻塞, 立刻返回, 不管是否有监控的事件发生
>0–到指定事件或者有事件发生了就返回

返回值: 成功返回发生变化的文件描述符的个数
失败返回-1, 并设置errno值.

/usr/include/x86_64-linux-gnu/sys/select.h和
/usr/include/x86_64-linux-gnu/bits/select.h
从上面的文件中可以看出, 这几个宏本质上还是位操作.

void FD_CLR(int fd, fd_set *set);
将fd从set集合中清除.
int FD_ISSET(int fd, fd_set *set);
功能描述: 判断fd是否在集合中
返回值: 如果fd在set集合中, 返回1, 否则返回0.
void FD_SET(int fd, fd_set *set);
将fd设置到set集合中.
void FD_ZERO(fd_set *set);
初始化set集合.

调用select函数其实就是委托内核帮我们去检测哪些文件描述符有可读数据,可写,错误发生;

代码思路:

代码的具体实现: 编写代码并进行测试.

可以使用发生事件的总数进行控制, 减少循环次数
调用select函数涉及到了用户空间和内核空间的数值交互过程.
事件一共包括两部分, 一类是新连接事件, 一类是有数据可读的事件

问题分析: select函数的readfds是一个传出传入参数

测试和总结select用法

关于select的思考:
问题: 如果有效的文件描述符比较少, 会使循环的次数太多.
解决办法: 可以将有效的文件描述符放到一个数组当中, 这样遍历效率就高了.

select优点:
1 一个进程可以支持多个客户端
2 select支持跨平台
select缺点:
1 代码编写困难
2 会涉及到用户区到内核区的来回拷贝
3 当客户端多个连接, 但少数活跃的情况, select效率较低
例如: 作为极端的一种情况, 3-1023文件描述符全部打开, 但是只有1023有发送数据, select就显得效率低下
4 最大支持1024个客户端连接
select最大支持1024个客户端连接不是有文件描述符表最多可以支持1024个文件描述符限制的, 而是由FD_SETSIZE=1024限制的.

FD_SETSIZE=1024 fd_set使用了该宏, 当然可以修改内核, 然后再重新编译内核, 一般不建议这么做.

作业:
编写代码, 让select监控标准输入, 监控网络, 如果标准输入有数据就写入网络, 如果网络有数据就读出网络数据, 然后打印到标准输出.
注意: select不仅可以监控socket文件描述符, 也可以监视标准输入.

预习内容:
poll epoll epoll反应堆

POSIX表示可移植操作系统接口(Portable Operating System Interface of UNIX,缩写为 POSIX ),POSIX标准定义了操作系统应该为应用程序提供的接口标准.

关于fd_set类型的底层定义:
/usr/include/x86_64-linux-gnu/sys/select.h和
/usr/include/x86_64-linux-gnu/bits/select.h
在/usr/include/x86_64-linux-gnu/sys/select.h文件中:

__NFDBITS计算出来的值是: 8*8=64

上面是在头文件中一步一步跟踪的定义, 最简单的方法就是使用预处理将头文件和宏全部替换掉, 直接就可以看到最终的定义了.
如: gcc -E select.c -o select.i
打开select.i后
typedef struct
{
__fd_mask __fds_bits[1024 / (8 * (int) sizeof (__fd_mask))];
} fd_set;
进一步转换后:
typedef struct
{
long int __fds_bits[1024/(8*8))];
//long int __fds_bits[16];
}
这个数组一共占用: 8 * 16 * 8 = 1024, 也就是说fd_set这个文件描述符表中一共有1024个bit位, 每个bit位只有0和1两种值, 1表示有, 0表示没有.

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

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

相关文章

JVM内存的变化

我举得&#xff0c;从空间的角度去理解java的运行&#xff0c;能更深刻的帮助我们学习后面“面向对象”的知识。因此&#xff0c;单独拿出一章&#xff0c;来解释内存的变化。以程序为实例进行判断。 需要一点JVM运行时的内存状态知识点基础。 参考博客&#xff1a; 这种是不…

ubuntu20.04 安装 Qt5.15

目录 安装前工作 选择安装QT的哪个版本 安装时候选择哪些组件 安装Qt5.15 在线安装 我选择的组件 源码包安装 测试 安装前工作 ubuntu20.04.3安装Qt6.22操作步骤_ubuntu安装qt6_sonicss的博客-CSDN博客 # 安装g、gcc编译器 sudo apt-get install build-essential 安装l…

leetcode 455. 分发饼干

2023.7.27 今天起福州要刮台风了&#xff0c;不过还是在宿舍坚持每日一题。 今天开始刷的系列属于贪心算法系列。本题是贪心算法的一个入门题。 贪心算法总体思路就是先找局部最优&#xff0c;在一步步的找出全局最优。 本题很明显全局最优就是 需要尽可能多投喂更多的孩子。…

「双指针技巧解决一些数组问题」

文章目录 0 分类1 快慢指针刷题1.1 删除有序数组中的重复项题解Code结果 1.2 删除排序链表中的重复元素题解Code结果 1.3 移除元素题解Code结果 1.4 移动0题解Code 2 左右指针刷题2.1 二分查找2.2 两数之和 II - 输入有序数组题解Code结果 2.3 反转字符串题解Code结果 2.4 最长…

品牌渠道管理的逻辑

无规矩不成方圆&#xff0c;规则确定了&#xff0c;接下来就是推行这个规则并且执行落地就可以&#xff0c;所以明确问题制定规则就非常重要。这个原则也适用于品牌渠道管理工作&#xff0c;品牌面对经销商低价乱价等问题时&#xff0c;如果仅用打击一种方式去管理&#xff0c;…

Component template should contain exactly one root element

在vue中报错&#xff1a; Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead报错的大致意思是&#xff1a;组件的模板应该只能包含一个根元素&#xff0c;也就是是说作为元素的直…

科技项目验收测试:验证软件产品功能与性能的有效手段

科技项目验收测试是验证软件产品功能与性能的重要手段&#xff0c;在项目开发中起到了至关重要的作用。本文将从产品质量、需求验证、性能测试等方面&#xff0c;探讨科技项目验收测试的有效手段。 1、产品质量保证是验收测试的核心 科技项目验收测试的核心目标是验证软件产品…

DFS()

DFS之连通性模型 dfs 与 bfs都能判断连通性 而且bfs可以得出最短距离 而dfs不可以 dfs 代码比较简洁 迷宫 一天Extense在森林里探险的时候不小心走入了一个迷宫&#xff0c;迷宫可以看成是由 n∗nn∗n 的格点组成&#xff0c;每个格点只有2种状态&#xff0c;.和#&#xff0…

【小尘送书-第三期】Python机器学习:基于PyTorch和Scikit-Learn 》

大家好&#xff0c;我是小尘&#xff0c;欢迎关注&#xff0c;一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的实习&#xff01; 本文目录 一、前言二、作者简介三、内容简介四、抽奖方式 一、前言 近年来&#xff0…

Vue-resource 实现 get, post请求

Vue-resource是Vue高度集成的第三方包&#xff0c;能很方便的发送请求。 注意Vue-resource依赖于Vue&#xff0c;只能在Vue环境下使用。 导包 //依赖于Vue <script src"./js/vue.js"></script> <script src"./js/elementui.js"></…

ROS与STM32通信-rosserial

文章目录 硬件接线 软件STM32CubeMX配置 rosserial移植上位机订阅-下位机发布上位机订阅下位机发布通信 上位机发布-下位机订阅上位机发布下位机订阅通信 硬件 STM32F103c8t6OLED(I2C)USB2TTLStlink 接线 OLED(GPIO模拟I2C) 硬件引脚OLEDSCLPA4OLEDSDAPA5 USART1 硬件引脚…

SwipeDelMenuLayout失效:Could not find SwipeDelMenuLayout-V1.3.0.jar

一、问题描述 最近在工作上的项目中接触到SwipeDelMenuLayout这个第三方Android开发库&#xff0c;然后我就根据网上的教程进行配置。这里先说一下我的开发环境&#xff1a;Android Studio版本是android-studio-2020.3.1.24-windows&#xff0c;gradle版本是7.0.2。 首先是在se…

LeetCode53.Maximum-Subarray<最大子数组和>

题目&#xff1a; 思路&#xff1a; 这题不会啊...然后发现题解如此简单, 逐层判断.得到最大值. 每次取得当前的最大值.并且更新结果最大值,结果循环扫描后得到结果 代码是&#xff1a; //codeclass Solution { public:int maxSubArray(vector<int>& nums) {int p…

【HarmonyOS】ArkTS自定义组件如何调用通用属性?

【关键词】 ArkTS、通用属性、 BuilderParam 【问题背景】 有个开发者使用ArkTS自定义了一个子组件AnimationButton&#xff0c;里面用到了装饰器 BuilderParam&#xff0c;在父页面中引用的时候使用自定义组件时&#xff0c;使用以下方式调用&#xff1a; 就报了这个错 【问…

基于双 STM32+FPGA 的桌面数控车床控制系统设计

桌 面数控 设 备 对 小 尺寸零件加工在成 本 、 功 耗 和 占 地 面 积等方 面有 着 巨 大 优 势 。 桌 面数控 设 备 大致 有 3 种 实 现 方 案 : 第 一种 为 微 型 机 床搭 配 传统 数控系 统 &#xff0c; 但 是 桌 面数控 设 备 对 成 本 敏感 ; 第二 种 为 基 于 PC…

《TCP IP网络编程》第十一章

第 11 章 进程间通信 11.1 进程间通信的基本概念 通过管道实现进程间通信&#xff1a; 进程间通信&#xff0c;意味着两个不同的进程中可以交换数据。下图是基于管道&#xff08;PIPE&#xff09;的进程间通信的模型&#xff1a; 可以看出&#xff0c;为了完成进程间通信&…

React入门学习笔记1

前言 React是一个用来动态构0建用户界面的JavaScript库&#xff08;只关注于视图&#xff09;。它可以帮助开发人员轻松地创建复杂的交互式界面&#xff0c;以及管理与用户交互的状态。相比于其他的JavaScript框架&#xff0c;React采用了一种不同的编程模型&#xff0c;称为“…

单片机中的通用LED驱动

前言 项目中需要用到很多的LED灯&#xff0c;存在不同的闪烁方式&#xff0c;比如单闪&#xff0c;双闪&#xff0c;快闪&#xff0c;慢闪等等&#xff0c;我需要一个有如下特性的LED驱动 方便的增加不同闪烁模式可以切换闪烁模式增加LED数目不会有太多的改动方便移植&#x…

《焊接点云处理》-V型焊缝处理

焊接点云处理-V型焊缝处理 前言一、代码二、处理步骤前言 处理效果 一、代码 主函数 #include "CGALRECONSTRUCT.h" #include"PCLFUNCTION.h"int main(int argc