网络通信-Linux 对网络通信的实现

Linux 网络 IO 模型

同步和异步,阻塞和非阻塞

同步和异步
关注的是调用方是否主动获取结果
         同步:同步的意思就是调用方需要主动等待结果的返回
        异步:异步的意思就是不需要主动等待结果的返回,而是通过其他手段比如,状态通知,
回调函数等。
阻塞和非阻塞
主要关注的是等待结果返回调用方的状态
         阻塞:是指结果返回之前,当前线程被挂起,不做任何事
        非阻塞:是指结果在返回之前,线程可以做一些其他事,不会被挂起。
两者的组合
        1 .同步阻塞:同步阻塞基本也是编程中最常见的模型,打个比方你去商店买衣服,你去了
之后发现衣服卖完了,那你就在店里面一直等,期间不做任何事(包括看手机),等着商家进
货,直到有货为止,这个效率很低。
        2.同步非阻塞:同步非阻塞在编程中可以抽象为一个轮询模式,你去了商店之后,发现衣
服卖完了,这个时候不需要傻傻的等着,你可以去其他地方比如奶茶店,买杯水,但是你还
是需要时不时的去商店问老板新衣服到了吗。
        3.异步阻塞:异步阻塞这个编程里面用的较少,有点类似你写了个线程池,submit 然后马
上 future.get(),这样线程其实还是挂起的。有点像你去商店买衣服,这个时候发现衣服没有
了,这个时候你就给老板留给电话,说衣服到了就给我打电话,然后你就守着这个电话,一
直等着他响什么事也不做。这样感觉的确有点傻,所以这个模式用得比较少。
        4.异步非阻塞:异步非阻塞。好比你去商店买衣服,衣服没了,你只需要给老板说这是我
的电话,衣服到了就打。然后你就随心所欲的去玩,也不用操心衣服什么时候到,衣服一到,
电话一响就可以去买衣服了

Linux 下的五种 I/O 模型

        总的来说, 阻塞 IO 就是 JDK 里的 BIO 编程,IO 复用就是 JDK 里的 NIO 编程,Linux 下异
步 IO 的实现建立在 epoll 之上,是个伪异步实现,而且相比 IO 复用,没有体现出性能优势,
使用不广。 非阻塞 IO 使用轮询模式,会不断检测是否有数据到达,大量的占用 CPU 的时间,
是绝不被推荐的模型。信号驱动 IO 需要在网络通信时额外安装信号处理函数,使用也不广。
 阻塞 IO 模型

 I/O 复用模型

        比较上面两张图,IO 复用需要使用两个系统调用 (select recvfrom) ,而 blocking IO
调用了一个系统调用 (recvfrom) 。但是,用 select 的优势在于它可以同时处理多个 connection
所以,如果处理的连接数不是很高的话,使用 select/epoll web server 不一定比使用
multi-threading + blocking IO web server 性能更好,可能延迟还更大。 select/epoll 的优势
并不是对于单个连接能处理得更快,而是在于能处理更多的连接。
Linux 代码结构看网络通信

 

         Linux 内核的源码包含的东西很多,在 Linux 的源代码中,网络设备驱动对应的逻辑位于
driver/net/ethernet, 其中 intel 系列网卡的驱动在 driver/net/ethernet/intel 目录下。 协议栈模
块代码位于 kernel net 目录。
        其中 net 目录中包含 Linux 内核的网络协议栈的代码。子目录 ipv4 ipv6 TCP/IP 协议
栈的 IPv4 IPv6 的实现,主要包含了 TCP UDP IP 协议的代码,还有 ARP 协议、 ICMP
议、 IGMP 协议代码实现,以及如 proc ioctl 等控制相关的代码。
        站在网络通信的角度,源代码组织的表现形式如下:
        网络协议栈是由若干个层组成的,网络数据的流程主要是指在协议栈的各个层之间的传递。
一个 TCP 服务器的流程按照建立 socket() 函数,绑定地址端口 bind() 函数,侦听端口 listen()
函数,接收连接 accept() 函数,发送数据 send() 函数,接收数据 recv() 函数,关闭 socket()
数的顺序来进行。
        与此对应内核的处理过程也是按照此顺序进行的,网络数据在内核中的处理过程主要是在
网卡和协议栈之间进行 : 从网卡接收数据,交给协议栈处理 ; 协议栈将需要发送的数据通过网
络发出去。
        由下图中可以看出,数据的流向主要有两种。应用层输出数据时,数据按照自上而下的顺
序,依次通过应用 API 层、协议层和接口层 ; 当有数据到达的时候,自下而上依次通过接口
层、协议层和应用 API 层的方式,在内核层传递。
        应用层 Socket 的初始化、绑定 (bind) 和销毁是通过调用内核层的 socket() 函数进行资源的申
请和销毁的。
        发送数据的时候,将数据由应用 API 层传递给协议层,协议层在 UDP 层添加 UDP 的首部、
TCP 层添加 TCP 的首部、 IP 层添加 IP 的首部,接口层的网卡则添加以太网相关的信息后,
通过网卡的发送程序发送到网络上。
        接收数据的过程是一个相反的过程,当有数据到来的时候,网卡的中断处理程序将数据从
以太网网卡的 FIFO 对列中接收到内核 , 传递给协议层 , 协议层在 IP 层剥离 IP 的首部、 UDP
剥离 UDP 的首部、 TCP 层剥离 TCP 的首部后传递给应用 API 层,应用 API 层查询 socket
标识后,将数据送给用户层匹配的 socket
        在 Linux 内核实现中,链路层协议靠网卡驱动来实现,内核协议栈来实现网络层和传输层。
内核对更上层的应用层提供 socket 接口来供用户进程访问。

 

Linux 下的 IO 复用编程

        select, poll epoll 都是 IO 多路复用的机制。 I/O 多路复用就是通过一种机制,一个进
程可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),能够通知程序
进行相应的读写操作。但 select poll epoll 本质上都是同步 I/O ,因为他们都需要在读写事
件就绪后自己负责进行读写,并等待读写完成。
文件描述符 FD
        在 Linux 操作系统中,可以将一切都看作是文件,包括普通文件,目录文件,字符设备
文件(如键盘,鼠标…),块设备文件(如硬盘,光驱…),套接字等等,所有一切均抽象
成文件,提供了统一的接口,方便应用程序调用。
既然在 Linux 操作系统中,你将一切都抽象为了文件,那么对于一个打开的文件,我应
用程序怎么对应上呢?文件描述符应运而生。
         文件描述符 File descriptor,简称 fd,当应用程序请求内核打开/新建一个文件时,内核
会返回一个文件描述符用于对应这个打开/新建的文件,其 fd 本质上就是一个非负整数。
际上,它是一个索引值,指向内核为每一个进程所维护的该进程打开文件的记录表。当程序
打开一个现有文件或者创建一个新文件时,内核向进程返回一个文件描述符。在程序设计中,
一些涉及底层的程序编写往往会围绕着文件描述符展开。但是文件描述符这一概念往往只适
用于 UNIX Linux 这样的操作系统。
        系统为了维护文件描述符建立了 3 个表:进程级的文件描述符表、系统级的文件描述符
表、文件系统的 i-node 表 。所谓进程级的文件描述符表,指操作系统为每一个进程维护了
一个文件描述符表,该表的索引值都从从 0 开始的,所以在不同的进程中可以看到相同的文
件描述符,这种情况下相同的文件描述符可能指向同一个实际文件,也可能指向不同的实际
文件
select
int select (int n, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval
*timeout);
        select 函数监视的文件描述符分 3 类, 分别是 writefds、readfds、和 exceptfds 。调用后
select 函数会阻塞,直到有描述副就绪(有数据 可读、可写、或者有 except ),或者超时
timeout 指定等待时间,如果立即返回设为 null 即可),函数返回。当 select 函数返回后,
可以 通过遍历 fdset ,来找到就绪的描述符。
        select 目前几乎在所有的平台上支持,其良好跨平台支持也是它的一个优点。 select
一 个缺点在于单个进程能够监视的文件描述符的数量存在最大限制,在 Linux 上一般为 1024
可以通过修改宏定义甚至重新编译内核的方式提升这一限制,但是这样也会造成效率的降低。
poll
int poll (struct pollfd *fds, unsigned int nfds, int timeout);
         不同与 select 使用三个位图来表示三个 fdset 的方式,poll 使用一个 pollfd 的指针实现。
pollfd 结构包含了要监视的 event 和发生的 event,不再使用 select“参数-值”传递的方
。同时, pollfd 并没有最大数量限制(但是数量过大后性能也是会下降)。 和 select 函数
一样, poll 返回后,需要轮询 pollfd 来获取就绪的描述符。
epoll
         epoll 是在 2.6 内核中提出的,是之前的 select 和 poll 的增强版本 。相对于 select poll
来说,可以看到 epoll 做了更细致的分解,包含了三个方法,使用上更加灵活。
int epoll_create(int size)
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);

int epoll_create(int size);
        创建一个 epoll 的句柄, size 用来告诉内核这个监听的数目一共有多大,这个参数不同
select() 中的第一个参数,给出最大监听的 fd+1 的值,参数 size 并不是限制了 epoll 所能
监听的描述符最大个数,只是对内核初始分配内部数据结构的一个建议。当创建好 epoll
柄后,它就会占用一个 fd 值,在 linux 下如果查看 /proc/ 进程 id/fd/ ,是能够看到这个 fd 的,
所以在使用完 epoll 后,必须调用 close() 关闭,否则可能导致 fd 被耗尽。
作为类比,可以理解为对应于 JDK NIO 编程里的 selector = Selector.open();
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event)
函数是对指定描述符 fd 执行 op 操作。
        epfd:是 epoll_create() 的返回值。
        op:表示 op 操作,用三个宏来表示:添加 EPOLL_CTL_ADD ,删除 EPOLL_CTL_DEL ,修
EPOLL_CTL_MOD 。分别添加、删除和修改对 fd 的监听事件。
        fd:是需要监听的 fd (文件描述符)
        epoll_event:是告诉内核需要监听什么事,有具体的宏可以使用,比如 EPOLLIN :表示
对应的文件描述符可以读(包括对端 SOCKET 正常关闭); EPOLLOUT :表示对应的文件描述
符可以写;
        作为类比,可以理解为对应于 JDK NIO 编程里的 socketChannel.register();
int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int timeout);
        等待 epfd 上的 io 事件,最多返回 maxevents 个事件。
        参数 events 用来从内核得到事件的集合, maxevents 告之内核这个 events 有多大,这 个 maxevents 的值不能大于创建 epoll_create() 时的 size ,参数 timeout 是超时时间(毫秒, 0
会立即返回, -1 将不确定,也有说法说是永久阻塞)。该函数返回需要处理的事件数目,
如返回 0 表示已超时。
        作为类比,可以理解为对应于 JDK NIO 编程里的 selector.select();

selectpollepoll 的比较

        select, poll epoll 都是 操作系统实现 IO 多路复用的机制。 我们知道, I/O 多路复用
就通过一种机制,可以监视多个描述符,一旦某个描述符就绪(一般是读就绪或者写就绪),
能够通知程序进行相应的读写操作。那么这三种机制有什么区别呢。
1 、支持一个进程所能打开的最大连接数

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

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

相关文章

TP-LINK AC1200 双频无线路由器网段设置

TP-LINK AC1200 双频无线路由器网段设置 1. 管理页面2. 上网设置3. 无线设置4. LAN 口设置 原始 3 网段5. LAN 口设置 设置 1 网段6. DHCP 服务器7. 重新连接References ​ 1. 管理页面 管理页面:http://tplogin.cn/ 上网方式:自动获得 IP 地址 2. 上网…

string类编程实例

2.9 string类编程实例 2.9 string类编程实例 实现一个字符串类String&#xff0c;为其提供可接受C风格字符串的析构函数、构造函数、拷贝构造函数和拷贝赋值函数 #include <iostream> #include <cstring> using namespace std;class String{ public:explicit Str…

Vue框架引入Element-Ui

首先已经创建好了 Vue 框架&#xff0c;安装好了 node.js。 没有完成的可按照此博客搭建&#xff1a;搭建Vue项目 之后打开终端&#xff0c;使用命令。 1、命令引入 npm i element-ui -S2、package.json 查看版本 在 package.json 文件里可查看下载好的依赖版本。 3、在 ma…

Python入门学习篇(八)——元组详解

1 相关概念以及理解 1 python的元组与列表类似,不同之处在于元组的元素不可修改 2 有序且可重复 3 语法: (值1,值2,值3...值n) 最简单的元组为(值,) 而这个(值)并不是元组 4 关键字 tuple 5 因为元组不可修改,我们重新赋值元组的时候,只是改变了指向关系, 原来的元组还是依然…

【Mybatis】深入学习MyBatis:概述、主要特性以及配置与映射

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; Mybatis ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 一、概述 MyBatis简介 主要特性 1. 动态SQL 2.结果映射 3 .插件机制 二、MyBatis配置文件 1.配置文件结构 数据库连…

连锁电商管理系统门店拓客+门店进销存管理+门店进货+总部进销存管理 整体系统搭建设计

搭建一个连锁电商管理系统需要考虑门店拓客、门店进销存管理、门店进货以及总部进销存管理等多个方面。以下是一个整体系统功能整理&#xff1a; 1. **门店拓客** - 实现线上线下渠道的融合&#xff0c;建立一个门店拓客平台&#xff0c;吸引潜在客户。 - 设计会员管理系统&…

【算法题】11. 盛最多水的容器

题目 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;你不能倾斜容器。…

tsconfig.app.json文件报红:Option ‘importsNotUsedAsValues‘ is deprecated...

在创建vue3 vite ts项目时的 tsconfig.json&#xff08;或者tsconfig.app.json&#xff09; 配置文件经常会报一个这样的错误&#xff1a; 爆红&#xff1a; Option ‘importsNotUsedAsValues’ is deprecated and will stop functioning in TypeScript 5.5. Specify compi…

Springboot实现定时任务

一、定时任务是什么&#xff1f; 定时执行任务&#xff0c;只有电脑不关机就可以在特定的时间去执行相应的代码&#xff0c;例如抢购脚本等 二、使用步骤 1.无需引入springboot自带 package com.ltx.blog_ltx;import org.springframework.boot.SpringApplication; import o…

Cause: java.sql.SQLTimeoutException: ORA-01013: 用户请求取消当前的操作

##oracle异常排查 ### Cause: java.sql.SQLTimeoutException: ORA-01013: 用户请求取消当前的操作 ; ORA-01013: 用户请求取消当前的操作 ; nested exception is java.sql.SQLTimeoutException: ORA-01013: 用户请求取消当前的操作 原因&#xff1a;sql语句操作超时了&#…

低代码:拒绝重复、低价值的工单循环开发

一、前言 在软件开发和其他工程领域&#xff0c;“重复造轮子”被广泛认为是一种低效的做法&#xff0c;因为它浪费了大量的时间和资源去重新创作已经存在的东西&#xff0c;而不是利用现有的技术和经验去解决问题。 例如在大平台项目的实战开发中&#xff0c;针对不同业务场景…

docker-compose部署kafka

docker-compose.yml配置 version: "3" services:kafka:image: bitnami/kafka:latestports:- 7050:7050environment:- KAFKA_ENABLE_KRAFTyes- KAFKA_CFG_PROCESS_ROLESbroker,controller- KAFKA_CFG_CONTROLLER_LISTENER_NAMESCONTROLLER- KAFKA_CFG_LISTENERSPLAIN…

63.乐理基础-打拍子-四十六

历史知识&#xff1a; 当前写的节奏型是四十六节奏型&#xff0c;同二八这个词的意思类似&#xff0c;四十六就是四个十六分音符组成的节奏型&#xff0c;所以简称四十六&#xff0c;以四分音符为一拍的时候&#xff0c;四个十六分音符加起来的总拍数就是一拍&#xff0c;这…

算法训练第四十八天|198. 打家劫舍、213. 打家劫舍 II、337. 打家劫舍 III

198. 打家劫舍&#xff1a; 题目链接 你是一个专业的小偷&#xff0c;计划偷窃沿街的房屋。每间房内都藏有一定的现金&#xff0c;影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统&#xff0c;如果两间相邻的房屋在同一晚上被小偷闯入&#xff0c;系统会自动报…

SpringBoot整合JWT+Spring Security+Redis实现登录拦截(二)权限认证

上篇博文中我们已经实现了登录拦截&#xff0c;接下来我们继续补充代码&#xff0c;实现权限的认证 一、RBAC权限模型 什么事RBAC权限模型&#xff1f; RBAC权限模型&#xff08;Role-Based Access Control&#xff09;即&#xff1a;基于角色的权限访问控制。在RBAC中&#x…

15.权限控制 + 置顶、加精、删除

目录 1.权限控制 1.1 登录检查 1.2 授权配置 1.3 认证方案 1.4 CSRF 配置 2.置顶、加精、删除 2.1 开发数据访问层 2.2 业务层 2.3 表现层 Spring Security 是一个专注于为 Java 应用程序提供身份认证和授权的框架&#xff0c;它的强大之处在于它可以轻松扩展以满足自…

蓝桥杯的学习规划

c语言基础&#xff1a; Python语言基础 学习路径&#xff1a;画框的要着重学习

一文读懂SoBit 跨链桥教程

从BTC网络到Solana网络桥接BRC20 1.打开SoBit平台&#xff1a;在您的网络浏览器中启动SoBit Bridge应用程序。 2.连接您的钱包&#xff1a; 选择SoBit界面右上角的比特币网络来连接您的数字钱包。 3.选择源链、目标链和您想桥接的代币&#xff1a; 从下拉菜单中选择’BTC’作为…

翻硬币C语言

分析&#xff1a;首先&#xff0c;我们如果想要使得两次的硬币可以转化&#xff0c;那么两组字符对应不同的的个数就只能是偶数&#xff0c;比如&#xff1a; * * * * * o o * * * * * 我们要对上面的例子翻动5次&#xff0c;我们可以看出两个不同的位置相差五个单位&#x…

用C/C++实现MSML协议栈的详细介绍

一、MSML协议简介 MSML&#xff08;Media Server Markup Language&#xff09;是一种基于XML的标记语言&#xff0c;用于控制媒体服务器。它是媒体服务器控制协议的一种&#xff0c;允许第三方应用与媒体服务器进行交互&#xff0c;实现对媒体流的创建、修改和释放等操作。MSM…