muduo源码阅读:socket常见操作及一些补充
TCP连接和释放
一个典型的TCP连接、通信过程:
(假设有资源的一端是服务器端)
服务器会启用一个监听循环,不断接受client连接请求(三次握手建立连接), 进行数据通信,通信完成以后断开连接(四次挥手断开连接)。
对于client,在server启用监听循环时,向server发出连接请求,接收server数据,如有必要向server发送数据,通信完成后,断开连接。
客户端 socket,bind,connet(变为主动套接字)。服务器socket,bind,listen(变为监听套接字),accpet。
连接是指物理上一端(client)到另一端(server)的通信链路,通过server端<ip, port>与客户端<ip, port>,来唯一标识一个TCP连接。

TCP连接有长连接、短连接之分:
短连接:client和server建立连接后,一般只传递一次读写操作,然后由client发起close,发送FIN分节,关闭连接。短连接只完成一次read/write操作,就会自动关闭。
长连接:client和server建立连接后,并不会自动关闭,后续的read/write操作会继续用这个连接。长连接没有确切时间限制,可能会长时间存在。
什么是读方向,什么是写方向 ?
读方向:从TCP连接中接收数据的操作。进程从TCP连接中读取来自远端的数据。应用程序正在执行读操作,它是在接收对方发送过来的数据。
写方向:通过TCP连接发送数据的操作。进程向TCP连接中写入数据以发送给远端的应用程序。执行写操作时,你是在向对方发送数据。
为什么“方向”会是操作?
以读方向为例:应用程序从网络接收数据的过程。在这个过程中,数据是从远程主机流向本地主机的。这里的“读”实际上是一个动作或操作,它代表的是本地进程从TCP连接中获取来自远端进程的数据的行为。
两个方向并不直接指向某个实体,而是描述了数据在两个网络节点之间的流动方式以及每个节点上的应用程序如何与这种流动进行交互。
close和shutdown有什么区别?
对于TCP连接来说,正常情况下应该先关闭写方向(即不再发送数据),然后继续处理可能还在传输中的数据(读方向)(参见下一个问题)。
直接调用close()会同时关闭读写两个方向,并释放套接字相关的资源。就是说调用close的一方不能读写另一方,相当于强制关闭连接。如果TCP缓冲区有残留数据没有读或写,会直接丢失。
close关闭连接和套接字
#include<unistd.h>
int close(int fd);
close会把描述符(sockfd)引用计数-1, 当计数为0时, 才真正断开连接、关闭套接字。
(引用计数联系软链接和硬连接,shared_ptr和其他垃圾回收算法)
close终止读、写两个方向的数据传送
对读方向, 内核将套接字设置为不可读, 任何读操作都会返回异常。
对写方向, 内核尝试将发送缓冲区中的数据发送给对端, 最后发送FIN分节, 接下来如果再对该套接字进行写操作会返回异常。如果对端还继续发送数据, 就会响应RST分节。
shutdown关闭连接的一个方向, 具体取决于参数how. 成功返回0; 失败为-1, errno被设置
#include<sys/socket.h>
int shutdown(int sockfd, int how);
how有3个值:
- SHUT_RD 关闭连接的读方向, 不能再通过套接字读取数据(读操作会直接返回EOF), 而且套接字接收缓冲区现有数据都被丢弃. 如果再收到新数据, 会对数据进行ACK, 然后直接丢弃.
- SHUT_WR 关闭连接的写方向, 常称为"半关闭 half-close". 现有发送缓冲区的数据将会被发送掉, 后跟FIN分节. 如果程序对该套接字进行写操作, 会报错。
- SHUT_RDWR 连接的读半部和写半部都关闭,与调用shutdown两次等效:shutdown(sockfd, SHUT_RD) + shutdown(sockfd, SHUT_WR)。
shutdown和close区别
close关闭2个方向连接, 并释放连接对应资源(套接字),而shutdown不会释放所有资源;close有引用计数的概念, 只有计数为0时, 才会释放套接字资源; shutdown没有引用计数, 是直接释放how指定的资源。close后, 只有引用计数为0时, 才会发送FIN分节。 以SHUT_WR或SHUT_RDWR为参数调用shutdown时, 总会发送FIN分节。
当服务器端调用close时,客户端对应的server fd(connet返回的文件描述符)会发生什么变化?
TCP连接的终止:
在服务器端调用 close(fd) 后,如果该 fd 是一个用于TCP通信的套接字描述符,并且这是最后一个指向该套接字的引用,那么这将启动TCP连接的正常关闭过程。服务器会尝试发送一个FIN包给客户端,表示它已经完成了数据发送。
客户端状态变化:
客户端会收到一个来自服务器的FIN包.此时,客户端的套接字进入CLOSE_WAIT状态,表明它已经收到了服务器关闭其写方向的通知。
如果客户端也有数据要发送完毕,则可以继续发送直到完成。一旦所有数据发送完毕,客户端应用程序应当也调用close()来关闭其对应的套接字文件描述符,客户端发送一个FIN包给服务器,通知服务器它也不会再发送数据了。
在客户端成功发送FIN后,客户端的套接字状态会从LAST_ACK转变为CLOSED,前提是它收到来自服务器对最后ACK的确认。
残留数据处理:在服务器端调用close()之后,如果还有未被客户端读取的数据留在TCP连接的缓冲区中,这些数据将会丢失,因为服务器端已明确表示不再继续该连接上的任何通信。
半关闭连接:如果你只想关闭某一方向的数据传输而非立即完全关闭连接,可以考虑使用shutdown()函数而不是close()。
什么是文件描述符的引用计数?
在Linux系统中,一个套接字的引用计数是指内核跟踪当前有多少个进程正在使用这个套接字。
使用引用计数防止了资源被提前释放或意外关闭。
在Linux内核中,多个进程或线程可能会共享同一个资源(如文件、套接字等)。为了确保这些资源在进程使用时不会被释放,内核对每个文件描述符使用引用计数来表示。每当一个新的进程开始使用一个资源时,相应的引用计数增加。当进程停止使用该资源时,引用计数减少。只有当引用计数降至0时,资源才会被真正释放。(与shared_ptr类似)
为什么一个套接字引用计数会大于0?
比如当你通过socket()系统调用来创建一个新套接字时,该套接字的引用计数初始为1。随着更多的进程或线程打开相同的套接字(如通过dup()或fork()后),引用计数相应增加。
每次对该套接字执行close()操作时,引用计数减1。只有当引用计数降到0时,套接字才会被彻底关闭,并且相关的资源会被回收。
假设有一个服务器程序,它创建了一个监听套接字用于接受客户端连接:
int listener = socket(AF_INET, SOCK_STREAM, 0);
bind(listener, ...); // 绑定地址和端口
listen(listener, ...); // 开始监听
此时,监听套接字的引用计数为1。如果一个客户端连接到这个服务器,服务器通过accept()接受连接:
int client_fd = accept(listener, ...);
这时,client_fd代表了一个新的套接字描述符,用于与客户端通信,而listener仍然保持打开状态以接受其他可能的连接。这里,listener的引用计数仍然是1,因为只有一个进程在使用它。
如果服务器程序通过fork()为每个客户端创建一个子进程来处理连接,那么每个子进程都会继承父进程中打开的文件描述符(包括监听套接字和其他已建立连接的套接字)。如果有5个子进程同时运行,监听套接字的引用计数将变为6(1个父进程+5个子进程)。
相关文章:
muduo源码阅读:socket常见操作及一些补充
TCP连接和释放 一个典型的TCP连接、通信过程: (假设有资源的一端是服务器端) 服务器会启用一个监听循环,不断接受client连接请求(三次握手建立连接), 进行数据通信,通信完成以后断开连接(四次挥手断开连接)。 对于…...
虚拟表格实现全解析
在数据展示越来越复杂的今天,大量数据的渲染就像是“满汉全席”——如果把所有菜肴一次性摆上桌,既浪费资源也让人眼花缭乱。幸运的是,我们有两种选择: 自己动手:通过二次封装 Element Plus 的表格组件,实…...
使用 Grafana 监控 Spring Boot 应用
随着软件开发领域的不断发展,监控和可观测性已成为确保系统可靠性和性能的关键实践。Grafana 是一个功能强大的开源工具,能够为来自各种来源的监控数据提供丰富的可视化功能。在本篇博客中,我们将探讨如何将 Grafana 与 Spring Boot 应用程序…...
使用Socket编写超牛的http服务器和客户端(一)
实现一个高性能的基于 IOCP(I/O Completion Ports)的 HTTP 服务器,支持多线程、动态线程池调整和路由处理。 主要功能和特性 IOCP 模型: 使用多个 IOCP 句柄(IOCP_COUNT),将客户端连接均匀分配到不同的 IOCP 上,减少线程竞争。 工作线程使用 GetQueuedCompletionStatu…...
python turtle模块有哪几种命令
python turtle模块命令的分类: 1、运动命令 2、笔画控制命令 3、其他命令...
【Transformer架构】
目录 一、Transformer介绍 1.1 Transformer的诞生 1.2 什么是Transformer 1.3 Transformer的优势 1.4 Transformer的市场 二、Transformer架构 2.1 Transformer模型的作用 2.2 Transformer总体架构图 2.2.1 Transformer总体架构 2.2.2 输入部分 2.2.3 输出部分 2.2.…...
unity学习50:NavMeshAgent 区域Areas和cost
目录 1 NavMeshAgent 区域和成本的问题 2 区域Areas 2.1 区域和颜色 2.2 区域和成本 2.3 区域成本的作用 2.4 地图测试准备 2.5 如何实现 2.5.1 unity的2022之前的老版本 2.5.2 unity的2022之后的新版本 2.6 如果测试失败,是因为没有bake 2.7 测试前&…...
Blender小技巧和注意事项
1.雕刻模式如果没反应,需要将模式转换成编辑模式 2. 鼠标移到大纲 点击 小键盘的. / 大键盘句号 , 在大纲视图快速找到选中物体 3.打包图像等数据进Blender文件中,可以防止丢失 4.拍摄小物体用长焦镜头 , 焦距120mm左右...
Python常见面试题的详解15
1. 死锁(Deadlock) 死锁指的是在多线程或者多进程的运行环境中,两个或多个线程(进程)彼此等待对方释放所占用的资源,进而陷入无限期等待的僵局,最终导致程序无法继续推进。 必要条件 互斥条件…...
代码审计初探
学会了基础的代码审计后,就该提高一下了,学一下一些框架的php代码审计 先从一些小众的、已知存在漏洞的cms入手 phpems php的一款开源考试系统 源码下载 https://down.chinaz.com/soft/34597.htm 环境部署 windows审计,把相关文件放到phps…...
Spring面试题2
1、compareable和compactor区别 定义与包位置:Comparable是一个接口,位于java.lang包,需要类去实现接口;而Compactor是一个外部比较器,位于java.util包 用法:Comparable只需要实现int compareTo(T o) 方法,比较当前对…...
Linux 权限系统和软件安装(二):深入理解 Linux 权限系统
在 Linux 的世界里,权限系统犹如一位忠诚的卫士,严密守护着系统中的文件与目录,确保只有具备相应权限的用户才能进行操作。与其他一些操作系统不同,Linux 并不依据文件后缀名来标识文件的操作权限,而是构建了一套独特且…...
二:前端发送POST请求,后端获取数据
接着一:可以通过端口访问公网IP之后 二需要实现:点击飞书多维表格中的按钮,向服务器发送HTTP请求,并执行脚本程序 向服务器发送HTTP请求: 发送请求需要明确一下几个点 请求方法: 由于是向服务器端发送值…...
单机上使用docker搭建minio集群
单机上使用docker搭建minio集群 1.集群安装1.1前提条件1.2步骤指南1.2.1安装 Docker 和 Docker Compose(如果尚未安装)1.2.2编写docker-compose文件1.2.3启动1.2.4访问 2.使用2.1 mc客户端安装2.2创建一个连接2.3简单使用下 这里在ubuntu上单机安装一个m…...
安全生产月安全知识竞赛主持稿串词
女:尊敬的各位领导、各位来宾 男:各位参赛选手、观众朋友们 合:大家好~ 女:安全是天,有了这一份天,我们的员工就会多一份幸福, 我们的企业就会多一丝光彩。 男:安全是地,有了这一片地,我们的员工就多了一…...
C++的设计模式
1. 创建型模式 单例模式 (Singleton) 意图:确保类仅有一个实例,并提供全局访问点。(常见的日志类)实现:class Singleton { private:static Singleton* instance;Singleton() {} // 私有构造函数 public:static Singl…...
C++手撕AVL树
C手撕AVL树 1、AVL树的概念2、AVL树的结构3、AVL树的插入3.1、大概过程3.2、更新平衡因子3.3、更新平衡因子代码3.4、左单旋3.5、右单旋3.6、右左双旋3.7、左右双旋 4、AVL树的删除5、AVL树的查找6、AVL树的平衡检测7、AVL树的其他函数完整代码 1、AVL树的概念 二叉搜索树虽可…...
写大论文的word版本格式整理,实现自动生成目录、参考文献序号、公式序号、图表序号
前情提要:最近开始写大论文,发现由于内容很多导致用老方法一个一个改的话超级麻烦,需要批量自动化处理,尤其是序号,在不断有增添删减的情况时序号手动调整很慢也容易出错,所以搞一个格式总结,记…...
Redission可重试、超时续约的实现原理(源码分析)
Redission遇到其他进程已经占用资源的时候会在指定时间waitTime内进行重试。实现过程如下: 执行获取锁的lua脚本时,会返回一个值, 如果获取锁成功,返回nil,也就是java里的null 如果获取锁失败,用语句“PT…...
java八股文-消息队列
一、MQ基础篇 1. 什么是消息队列? 消息队列(MQ)是分布式系统中实现异步通信的中间件,解耦生产者和消费者。 2. 使用场景有哪些? 异步处理(如注册后发送邮件)系统解耦(不同服务通过…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
如何在看板中体现优先级变化
在看板中有效体现优先级变化的关键措施包括:采用颜色或标签标识优先级、设置任务排序规则、使用独立的优先级列或泳道、结合自动化规则同步优先级变化、建立定期的优先级审查流程。其中,设置任务排序规则尤其重要,因为它让看板视觉上直观地体…...
【大模型RAG】Docker 一键部署 Milvus 完整攻略
本文概要 Milvus 2.5 Stand-alone 版可通过 Docker 在几分钟内完成安装;只需暴露 19530(gRPC)与 9091(HTTP/WebUI)两个端口,即可让本地电脑通过 PyMilvus 或浏览器访问远程 Linux 服务器上的 Milvus。下面…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
[10-3]软件I2C读写MPU6050 江协科技学习笔记(16个知识点)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
