Socket套接字(客户端,服务端)和IO多路复用

news2024/11/30 0:35:32

Socket套接字(客户端,服务端)

目录

    • socket是什么
    • 一、在客户端
        • 1. 创建套接字
        • 2. 设置服务器地址
        • 3. 连接到服务器
        • 4. 发送数据
        • 5. 接收数据
        • 6. 关闭连接
    • 二、内核态与用户态切换
    • 三、系统调用与上下文切换的关系
    • 四、在服务端
        • 1. 创建 Socket (用户态)
        • 2. 绑定
        • 3. 监听
        • 4. 接受连接
        • 5. 接收消息 (用户态 -> 内核态)
    • 五、IO多路复用
        • 主要区别
        • 1. select()
        • 2. poll()
        • 3. epoll()
        • epoll工作模式
        • select()开销
        • 位图是什么

socket是什么

Socket(套接字) 是一种用于在网络中进行进程间通信(一般是不同主机之间进程)的编程接口。它提供了一种标准的方法,使得不同计算机上的应用程序能够相互通信。

一、在客户端

通过套接字(SOCKET)在客户端和服务器之间传输数据是网络编程中的一种常见方式。下面是详细步骤,包括相关的内核态和用户态切换的说明。

1. 创建套接字
  • 用户态
    在客户端使用系统调用 socket() 创建一个套接字。
  • 内核态
    系统调用进入内核态,内核为套接字分配资源并返回文件描述符。
2. 设置服务器地址
  • 用户态
    定义服务器的地址结构并设置相关信息,如 IP 地址和端口号。
    代码示例:
3. 连接到服务器
  • 用户态
    使用 connect() 系统调用发起连接。
  • 内核态
    连接请求被发送到服务器,内核处理 TCP 握手(SYN、SYN-ACK、ACK)以建立连接。
4. 发送数据
  • 用户态
    使用 send()write() 系统调用发送数据

  • 内核态
    数据被复制到内核缓冲区,内核负责将数据打包并通过网络协议栈发送到服务器。

5. 接收数据
  • 用户态
    使用 recv()read() 系统调用接收来自服务器的数据。
  • 内核态
    内核检查网络接口接收缓冲区,若有数据则将数据复制到用户空间的缓冲区,并返回接收到的字节数。
6. 关闭连接
  • 用户态
    使用 close() 系统调用关闭套接字。
  • 内核态
    内核释放与套接字相关的资源,处理 TCP 的四次挥手(FIN、FIN-ACK、ACK)以关闭连接。

二、内核态与用户态切换

  • 当用户态程序调用系统调用(如 socket()connect()send()recv() 等)时,CPU 从用户态切换到内核态,执行内核中的相关函数。
  • 完成内核任务后,内核会将控制权返回给用户态程序,继续执行。
  • 系统调用作为软中断:系统调用本质上是一种软件中断(也称为“软中断”)

三、系统调用与上下文切换的关系

系统调用确实涉及到 CPU 上下文切换

  1. 用户态与内核态

    • 在现代操作系统中,CPU 有两种运行模式:用户态和内核态。用户态是应用程序运行的状态,而内核态是操作系统内核执行的状态。
    • 系统调用通常发生在用户态到内核态的切换。
  2. 发起系统调用

    • 当应用程序需要访问硬件资源或执行特权操作(如文件读写、网络通信等)时,它会通过特定的系统调用接口发起请求。这一请求会触发一个软中断,或者直接调用一个特殊的指令(如 syscallint 指令)。
  3. 上下文切换步骤

    • 保存当前上下文:在发起系统调用时,操作系统需要保存当前用户程序的执行状态(包括寄存器内容、程序计数器等),以便在返回时能够继续执行。
    • 切换到内核态:操作系统会将 CPU 模式从用户态切换到内核态,并开始执行相应的系统调用处理程序。
    • 执行系统调用:内核根据系统调用的类型执行具体操作。
    • 恢复上下文:系统调用完成后,操作系统将之前保存的用户程序上下文恢复,并将 CPU 模式从内核态切换回用户态。
    • 继续执行:最后,控制权返回给用户程序,继续其执行。

四、在服务端

1. 创建 Socket (用户态)
2. 绑定
3. 监听
4. 接受连接

服务端通过 accept 方法阻塞等待客户端的连接。

当有客户端尝试连接时:
内核态会处理 TCP 三次握手。
连接建立,accept() 方法将返回一个新的 socket 对象(用于与客户端通信)以及客户端的地址信息。

socket返回一个fd(文件描述符),对fd的操作就是对io文件流的操作。

准备 fd_set(select方法特有),在使用 select() 之前,你需要创建并初始化一个 fd_set 结构体,来表示你希望监控的文件描述符(FD)。这个结构体可以包含多个 socket 描述符
除了select()使用的 fd_set(位图),还可能是数组(poll),红黑树/链表(epoll)

调用 select() 函数
一旦你设置好 fd_set,就可以调用 select() 函数。这个函数会阻塞,直到至少有一个 socket 变为就绪状态。

处理就绪的 Socket
当 select() 返回后,需要检查哪个 socket 已经就绪。这可以通过再次遍历你的 fd_set 来完成

5. 接收消息 (用户态 -> 内核态)

服务端使用 recv 方法接收数据。

用户态发起 recv 调用,请求从 socket 中读取数据。
控制权切换到内核态,内核检查是否有可读的数据。
如果有数据,内核将数据复制到进程的地址空间(用户态),然后返回给用户态。

五、IO多路复用

与多进程和多线程技术相比,IO 多路复用技术的最大优势是系统开销小,系统不必创建进程或线程,也不必维护这些进程,从而大大减小了系统的开销。
select()、poll() 和 epoll() 都是用于实现 I/O 多路复用的系统调用

主要区别
特性select()poll()epoll()
文件描述符限制限制为 FD_SETSIZE(通常为1024)没有限制没有限制
数据结构位图数组红黑树/链表
性能性能随监视的文件描述符数量增加而降低能够处理较多的文件描述符性能稳定,尤其在监视大量文件描述符时
灵活性不灵活,需每次调用前设置相对灵活,能够处理

在这里插入图片描述

1. select()
  • 用户进程需要监控某些资源 fds,在调用 select 函数后会阻塞,操作系统会将用户线程加入这些资源的等待队列中。
  • select() 的内部实现通常使用一个时间轮询机制,通过不断检查每个文件描述符的状态来判断其是否就绪。
  • 直到有fd就绪(有数据可读、可写或有 except异常)或超时(timeout 指定等待时间,如果立即返回设为 null
    即可),函数返回。
  • select 函数返回后,中断程序唤起用户线程。用户可以遍历 fds,通过 FD_ISSET 判断具体哪个 fd
    收到数据,并做出相应处理。

优点

  • 简单,易于理解和使用。
  • 标准化,几乎所有 UNIX-like 操作系统都支持。

缺点

  • 文件描述符数量受到限制,32 位系统最多能监听 1024 个 fd,64 位最多监听 2048 个。
  • 每次调用 select 都需要将进程加入到所有监视 fd 的等待队列,每次唤醒都需要从每个队列中移除。 这里涉及了两次遍历,而且每次都要将整个 fd_set 列表传递给内核,有一定的开销。
  • 当函数返回时,系统会将就绪描述符写入 fd_set 中,并将其拷贝到用户空间。进程被唤醒后,用户线程并不知道哪些 fd 收到数据,还需要遍历一次。
  • 对于大量的文件描述符,性能会显著降低。
2. poll()
  • 数组结构:poll() 使用一个结构体数组(struct pollfd)来存储要监视的文件描述符及其事件类型。这使得它能够监视更多的文件描述符,而不受 FD_SETSIZE 的限制。
  • 事件标志:每个文件描述符都可以设置多个事件类型,如可读、可写等,并且可以通过事件结果获取哪些事件发生了。

优点

  • 没有文件描述符数量的硬性限制(受限于系统资源)。
  • 适合处理大量的文件描述符。

缺点

  • 和 select 函数一样,poll 返回后,需要轮询 pollfd 来获取就绪的描述符。
  • 事件检测偏向线性搜索,对于高负载场景性能较差。
3. epoll()

步骤:

  1. 创建 epoll 实例:调用 epoll_create() 或 epoll_create1() 来创建一个 epoll 实例,这将返回一个用于后续操作的文件描述符。
  2. 注册文件描述符
  3. 等待事件:当注册的文件描述符上发生事件时,可以调用 epoll_wait() 阻塞等待事件的发生。该函数会填充就绪的事件信息。
  4. 处理事件:根据 epoll_wait() 返回的就绪事件,进行相应的处理。每个事件包含了发生事件的文件描述符和事件类型,应用程序可以据此决定如何响应。
  5. 修改或删除事件:在事件处理过程中,如果需要修改现有的事件或从 epoll 中删除某个文件描述符,可以再次调用 epoll_ctl()。
  6. 清理资源

epoll 主要基于事件通知机制,它允许用户注册需要监控的文件描述符,并在这些文件描述符上发生特定事件时得到通知。与 select() 和 poll() 的线性扫描不同,epoll 使用了一种基于事件的模型,可以显著提高性能。

epoll 使用一个文件描述符管理多个描述符,将用户进程监控的文件描述符的事件存放到内核的一个事件表中,这样在用户空间和内核空间只需拷贝一次。

所有 FD 集合采用红黑树存储,就绪 FD 集合使用链表存储。这是因为就绪 FD 都需要处理,业务优先级需求,最好的选择便是线性数据结构。
优点

  • 高效,尤其适合大量文件描述符的情况,性能不会随着监视的文件描述符数量增加而明显下降。
  • 支持边缘触发和水平触发模式,可以更灵活地管理事件。

缺点

  • 仅在 Linux 环境下可用
epoll工作模式

1)LT模式

LT(level triggered)模式:也是默认模式,即当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件,并且下次调用 epoll_wait 时,会再次响应应用程序并通知此事件。

2)ET模式

ET(edge-triggered)模式:当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用epoll_wait时,不会再次响应应用程序并通知此事件。

ET 是一种高速工作方式,很大程度上减少了 epoll 事件被重复触发的次数。epoll 工作在 ET 模式的时候,必须使用非阻塞套接口,以避免由于一个文件句柄的阻塞读/阻塞写操作把处理多个文件描述符的任务饿死。

为何高效
1) epoll 精巧的使用了 3 个方法来实现 select 方法要做的事,分清了频繁调用和不频繁调用的操作。

epoll_ctrl 是不太频繁调用的,而 epoll_wait 是非常频繁调用的。而 epoll_wait 却几乎没有入参,这比 select 的效率高出一大截,而且,它也不会随着并发连接的增加使得入参越发多起来,导致内核执行效率下降。

2) mmap 的引入,将用户空间的一块地址和内核空间的一块地址同时映射到相同的一块物理内存地址(不管是用户空间还是内核空间都是虚拟地址,最终要通过地址映射映射到物理地址),使得这块物理内存对内核和对用户均可见,减少用户态和内核态之间的数据交换。

3)红黑树将存储 epoll 所监听的 FD。高效的数据结构,本身插入和删除性能比较好,时间复杂度O(logN)。

select()开销
  1. 调用过程中的开销

当你调用 select() 时,通常需要进行以下几个步骤:

  • 设置文件描述符集合:在用户空间中,你需要创建并初始化一个 fd_set 结构,包含所有你希望监视的文件描述符。这一步需要你手动管理这个集合。

  • 进入系统调用:在进行 select() 系统调用时,整个 fd_set 集合会被传递给内核。因为 fd_set 是一个位图,表示一组文件描述符的信息,内核需要扫描这个集合来检查每个文件描述符的状态(可读、可写等)。这意味着内核会在进入系统调用时遍历你的 fd_set,检查每一个文件描述符的状态。

  • 注册等待:内核将进程加入到所有这些文件描述符的等待队列中,每个文件描述符都有自己的等待队列。(当多个进程或线程对同一文件描述符执行 I/O 操作时,可能会出现需要等待的情况,所以每个文件描述符都有自己的等待队列。)当某个文件描述符变为就绪状态时,内核会将进程从这个队列中移除,从而唤醒进程。这就涉及到了两次遍历:一次是检查所有文件描述符的状态,另一次则是在返回时将进程从对应的队列中移除。

  1. 返回结果时的开销

select() 函数返回时,内核会更新你的 fd_set 结构,标记哪些文件描述符已经就绪。此时,内核需要将这些状态信息拷贝回用户空间。这个过程也有几步:

  • 填充 fd_set:内核会根据它所监视的文件描述符状态,更新你的 fd_set 结构。这种更新是基于内核对文件描述符的实际状态的判断。

  • 拷贝到用户空间:更新完成后,内核需要将这个更新的 fd_set 结构拷贝到你的程序的用户空间,因为用户程序需要知道哪些文件描述符现在可以进行 I/O 操作。

  1. 用户层处理

一旦 select() 返回,用户线程接下来要处理的是已就绪的文件描述符。即便内核已经在 fd_set 中更新了状态,用户还是需要遍历这个 fd_set,找出哪些文件描述符已经准备好进行操作。这意味着:

  • 用户程序需要再次遍历 fd_set,这增加了额外的开销。
  • 这也使得处理逻辑更加复杂,因为用户需要解析哪些文件描述符是就绪的,并做相应的处理。
位图是什么

位图(Bitmap)是一种用于表示集合的高效数据结构,它使用一组位(binary digits,0 和 1)来表示某个元素是否存在于集合中。这种表示方式非常节省空间并且可以快速进行查找、插入和删除等操作。

位图的基本概念

  • 每个位表示一个元素:在位图中,每一个位置对应一个特定的元素。例如,如果你有一个最多包含 n 个元素的集合,那么可以用 n 个位来表示。
    • 如果某一位为 1,则表示该元素在集合中。
    • 如果某一位为 0,则表示该元素不在集合中。

示例

假设我们有一个整数集合 {0, 2, 3, 5},我们可以使用位图来表示这个集合。假设我们的集合元素范围是从 0 到 7(即 8 个可能的元素),那么我们就可以用 8 位来表示:

元素索引: 0  1  2  3  4  5  6  7
位图:     1  0  1  1  0  1  0  0

在这个例子中:

  • 位图的第 0 位为 1,表示 0 存在于集合中。
  • 位图的第 1 位为 0,表示 1 不在集合中。
  • 位图的第 2 位为 1,表示 2 存在于集合中。
  • 以此类推。

位图的优点

  1. 空间效率:相较于其他数据结构(如链表),位图在存储稀疏集合时占用更少的空间。
  2. 快速访问:可以通过简单的位运算快速检查元素是否存在、添加或删除元素,例如使用位与(AND)、位或(OR)等操作。
  3. 简化算法:位图可以使一些算法变得更加简单和高效,特别是在处理大规模数据和稀疏数组时。

位图的缺点

  1. 固定大小:位图需要预先定义范围,如果元素超出这个范围,将会导致无法再添加新的元素。
  2. 浪费空间:如果集合中的元素分布稀疏,位图可能会造成大量未使用的位,从而浪费空间。

应用场景

  • 集合操作:如求并集、交集、差集等。
  • 内存管理:用于表示内存块的使用情况,例如进程的页表。
  • 网络协议:用于标识已收到的数据包。
  • 图像处理:在某些情况下,可以用位图表示像素状态。

总结
位图是一种非常有效率的数据结构,尤其适用于那些元素范围固定且需要频繁查询的场合。它的优势在于极大的提升了元素存在性检测的速度,并且在某些应用中提供了显著的空间节约。

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

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

相关文章

【Linux】进程地址空间(初步了解)

文章目录 1. 奇怪的现象2. 虚拟地址空间3. 关于页表4. 为什么要有虚拟地址 1. 奇怪的现象 我们先看一个现象: 为什么父子进程从“同一块地址中”读取到的值不一样呢? 因为这个地址不是物理内存的地址 ,如果是物理内存的地址是绝对不可能出…

C++【类和对象】(友元、内部类与匿名对象)

文章目录 1.友元2.内部类3.匿名对象结语 1.友元 友元提供了⼀种突破类访问限定符封装的方式,友元分为:友元函数和友元类,在函数声明或者类声明的前面加friend,并且把友元声明放到⼀个类的里面。外部友元函数可访问类的私有和保护…

【安全科普】从“微信文件助手隐私泄漏”看社交平台网络安全

随着互联网技术的飞速发展,社交平台已经成为了人们日常生活中不可或缺的一部分。人们通过社交平台与亲朋好友保持联系,分享生活点滴,获取资讯信息。然而,与此同时,社交平台上的网络安全风险也日益凸显。近期&#xff0…

简单的a+b-C语言

1.问题: 输入两个整数a和b,计算ab的和。 2.解答: scanf()函数是通用终端格式化输入函数,它从标准输入设备(键盘) 读取输入的信息。可以读入任何固有类型的数据并自动把数值变换成适当的机内格式。 scanf()函数返回值分为3种&…

分布式学习02-CAP理论

文章目录 CAP三指标一致性可用性分区容错性 CAP不可能三角P存在的必要性CP理论AP理论 CAP理论对分布式系统的特性做了高度抽象,将其抽象为一致性、可用性、分区容错性。 并对特征间的冲突做了总结:CAP不可能三角。 CAP三指标 一致性(Consis…

【NIO基础】基于 NIO 中的组件实现对文件的操作(文件编程),FileChannel 详解

目录 1、FileChannel (1)获取 FileChannel (2)读取文件 (3)写入文件 (4)关闭通道 (5)当前位置与文件大小 (6)强制写入磁盘 2、两个 FileChannel 之间的数据传输 (1)使用 transferTo()…

HTML的修饰(CSS) -- 第三课

文章目录 前言一、CSS是什么?二、使用方式1. 基本语法2. 引入方式1.行内式2.内嵌式3. 链入式 3. 选择器1. 标签选择器2.类选择器3. id选择器4. 通配符选择器 4. css属性1. 文本样式属性2. 文本外观属性 5. 元素类型及其转换1. 元素的类型2. 元素的转换 6.css高级特性…

isinstance()学习

aa {} if isinstance(aa,dict):print("是")aa 2 if isinstance(aa,dict):print("是")aa 2 if isinstance(aa,int):print("是")aa [] if isinstance(aa,list):print("list")aa [1,2,3] if isinstance(aa,list):print("list"…

模拟算法(4)_外观数列

个人主页:C忠实粉丝 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C忠实粉丝 原创 模拟算法(4)_外观数列 收录于专栏【经典算法练习】 本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌 目录 1. 题目链…

选择排序:直接选择排序、堆排序

目录 直接选择排序 1.选择排序的基本思想 2.直接选择排序的基本思想 3.直接插入排序的代码思路步骤 4.直接选择排序代码 5.直接选择排序的特性总结 堆排序 一、排升序,建大堆 1.利用向上调整函数建大堆 1.1.建立大堆的思路 1.2.以下是具体步骤&#xff1a…

Android Framework AMS(01)AMS启动及相关初始化1-4

该系列文章总纲链接:专题总纲目录 Android Framework 总纲 本章关键点总结 & 说明: 说明:本章节主要涉及systemserver启动AMS及初始化AMS相关操作。同时由于该部分内容分析过多,因此拆成2个章节,本章节是第一章节&…

Solidity 存储和内存管理:深入理解与高效优化

在 Solidity 中,存储和内存管理是编写高效智能合约的关键组成部分。合约执行的每一步操作都可能涉及到数据的存储和读取,而这些操作对 gas 的消耗有很大影响。因此,理解 Solidity 的存储模型以及如何优化数据的管理对于合约的安全性、性能和成…

pytorch之梯度累加

1.什么是梯度? 梯度可以理解为一个多变量函数的变化率,它告诉我们在某一点上,函数的输出如何随输入的变化而变化。更直观地说,梯度指示了最优化方向。 在机器学习中的作用:在训练模型时,我们的目标是最小…

day2网络编程项目的框架

基于终端的 UDP云聊天系统 开发环境 Linux 系统GCCUDPmakefilesqlite3 功能描述 通过 UDP 网络使服务器与客户端进行通信吗,从而实现云聊天。 Sqlite数据库 用户在加入聊天室前,需要先进行用户登录或注册操作,并将注册的用户信息&#xf…

P4、P4D、HelixSwarm 各种技术问题咨询

多年大型项目P4仓库运维经验,为你解决各种部署以及标准工业化流程问题。 Perforce 官网SDPHelixCore GuideHelixSwarm GuideHelixSwarm Download

SpringBoot基础(三):Logback日志

SpringBoot基础系列文章 SpringBoot基础(一):快速入门 SpringBoot基础(二):配置文件详解 SpringBoot基础(三):Logback日志 目录 一、日志依赖二、日志格式1、记录日志2、默认输出格式3、springboot默认日志配置 三、日志级别1、基础设置2、…

家长们,你们认为孩子沉迷游戏严重还是沉迷Linux严重呢

matrix禁食 ​ 计算机技术与软件专业技术资格证持证人 ​ 关注 谢邀 Hieronymus no-sh 218 人赞同了该回答 十年前,你还能得到一个自己能控制的计算机系统,现在,窗口期早走过了。普通人不懂软件,但因该懂人心啊,人心一…

使用Apifox创建接口文档,部署第一个简单的基于Vue+Axios的前端项目

前言 在当今软件开发的过程中,接口文档的创建至关重要,它不仅能够帮助开发人员更好地理解系统架构,还能确保前后端开发的有效协同。Apifox作为一款集API文档管理、接口调试、Mock数据模拟为一体的工具,能够大幅度提高开发效率。在…

武汉自闭症儿童寄宿学校:开启学习与成长的新篇章

武汉与广州的自闭症教育之光:星贝育园开启学习与成长新篇章 在自闭症儿童教育的广阔领域,寄宿学校以其独特的教育模式和全方位的关怀,为这些特殊孩子提供了学习、成长与融入社会的宝贵机会。虽然本文标题提及了武汉自闭症儿童寄宿学校&#…

【HTML+CSS】仿电子美学打造响应式留言板

创建一个响应式的留言板 在这篇文章中,我们将学习如何创建一个简单而美观的留言板,它将包括基本的样式和动画效果,以及响应式设计,确保在不同设备上都能良好显示。 HTML 结构 首先,我们创建基本的HTML结构。留言板由…