当前位置: 首页 > news >正文

Redis的实现二: c、c++的网络通信编程技术,让服务器处理多个client

       看过上期的都知道,我是搞java的,所以对这些可能理解不是很清楚,各位看完可以尽情发言。

事件循环和非阻塞IO

      在服务器端网络编程中,有三种处理并发连接的方法。
      它们是:分叉多线程事件循环。分叉为每个客户端连接创建新进程,以实现并发性。多线程使用线程而不是进程。事件循环使用轮询和非阻塞IO,通常在单个线程上运行。由于进程和线程的开销,大多数现代生产级软件使用事件循环进行网络连接。
我们服务器的事件循环的简化伪代码是:


all_fds = [...]
while True:active_fds = poll(all_fds)
for each fd in active_fds:do_something_with(fd)
def do_something_with(fd):if fd is a listening socket:add_new_client(fd)elif fd is a client connection:while work_not_done(fd):do_something_to_client(fd)def do_something_to_client(fd):if should_read_from(fd):data = read_until_EAGAIN(fd)process_incoming_data(data)while should_write_to(fd):write_until_EAGAIN(fd)
if should_close(fd):destroy_client(fd)

  1. all_fds 是一个包含所有需要监控的文件描述符的列表。
  2. while True: 是一个无限循环,它会一直运行,直到程序被外部中断。
  3. active_fds = poll(all_fds) 调用poll函数,返回一个包含所有准备好进行I/O操作的文件描述符的列表。
  4. for each fd in active_fds: 遍历这个列表,对每个文件描述符执行相应的操作。
  5. do_something_with(fd) 是一个函数,根据文件描述符的类型执行相应的操作。
  6. def do_something_with(fd): 定义了这个函数。
  7. if fd is a listening socket: 如果文件描述符是一个监听套接字,那么调用 add_new_client(fd) 函数添加新的客户端连接。
  8. elif fd is a client connection: 如果文件描述符是一个客户端连接,那么进入一个循环,直到工作完成为止。在这个循环中,调用 do_something_to_client(fd) 函数处理客户端的数据。
  9. def do_something_to_client(fd): 定义了这个函数。
  10. if should_read_from(fd): 如果应该从文件描述符读取数据,那么调用 read_until_EAGAIN(fd) 函数读取数据,然后调用 process_incoming_data(data) 函数处理数据。
  11. while should_write_to(fd): 如果应该向文件描述符写入数据,那么调用 write_until_EAGAIN(fd) 函数写入数据。
  12. if should_close(fd): 如果应该关闭文件描述符,那么调用 destroy_client(fd) 函数销毁客户端连接。

       我们不只是对fd做一些事情(读、写或接受),而是使用轮询操作来告诉我们哪些fd可以立即操作而不阻塞。当我们在fd上执行IO操作时,该操作应该在非阻塞模式下执行。

epoll的使用

        在Linux上,除了poll系统调用,还有select和epoll。古老的select系统调用基本上与轮询相同,只是最大fd数被限制为一个小数目,这使得它在现代应用程序中已经过时了。epoll API由3个系统调用组成:epoll_create、epoll_wait和epoll_ctl。epoll API是有状态的,而不是提供一组fd作为系统调用参数,epoll_ctl用于操作由epoll_create创建的fd集,epoll_wait正在对其进行操作。

       epoll API执行与poll()类似的任务:监视多个文件描述符,以查看其中任何一个文件是否可以进行I/O操作。epoll API可以用作边缘触发或水平触发接口,并且可以很好地扩展到大量监视的文件描述符。以下提供系统调用来创建和管理epoll实例:

       epoll_create()创建一个epoll实例并返回一个引用该实例的文件描述符。

       然后通过epoll_ctl()注册对特定文件描述符的兴趣。当前在epoll上注册的文件描述符集,实例有时称为epoll集。

       epoll_wait()等待I/O事件,如果当前没有事件可用,则阻塞调用线程。

           #define MAX_EVENTS 10struct epoll_event ev, events[MAX_EVENTS];int listen_sock, conn_sock, nfds, epollfd;/* Set up listening socket, 'listen_sock' (socket(),bind(), listen()) */epollfd = epoll_create(10);if (epollfd == -1) {perror("epoll_create");exit(EXIT_FAILURE);}ev.events = EPOLLIN;ev.data.fd = listen_sock;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1) {perror("epoll_ctl: listen_sock");exit(EXIT_FAILURE);}for (;;) {nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);if (nfds == -1) {perror("epoll_pwait");exit(EXIT_FAILURE);}for (n = 0; n < nfds; ++n) {if (events[n].data.fd == listen_sock) {conn_sock = accept(listen_sock,(struct sockaddr *) &local, &addrlen);if (conn_sock == -1) {perror("accept");exit(EXIT_FAILURE);}setnonblocking(conn_sock);ev.events = EPOLLIN | EPOLLET;ev.data.fd = conn_sock;if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock,&ev) == -1) {perror("epoll_ctl: conn_sock");exit(EXIT_FAILURE);}} else {do_use_fd(events[n].data.fd);}}}

       这段代码的主要功能是创建一个监听套接字,并使用epoll机制来处理客户端连接请求。以下是代码的详细解析:

  1. #define MAX_EVENTS 10:定义了一个宏常量MAX_EVENTS,表示最多可以处理的事件数量为10。
  2. struct epoll_event ev, events[MAX_EVENTS];:定义了一个结构体数组events,用于存储epoll事件。每个事件由一个epoll_event结构体表示。
  3. int listen_sock, conn_sock, nfds, epollfd;:定义了四个整型变量,分别表示监听套接字、新连接的套接字、返回的文件描述符数量和epoll实例的文件描述符。
  4. epollfd = epoll_create(10);:创建了一个epoll实例,最大文件描述符数量为10。如果创建失败,将打印错误信息并退出程序。
  5. ev.events = EPOLLIN;:设置事件类型为可读事件(EPOLLIN)。
  6. ev.data.fd = listen_sock;:将监听套接字的文件描述符设置为事件的关联数据。
  7. if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1):将监听套接字添加到epoll实例中,以便接收新的连接请求。如果添加失败,将打印错误信息并退出程序。
  8. for (;;):无限循环,不断处理事件。
  9. nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);:调用epoll_wait函数等待事件发生。参数-1表示等待所有类型的事件。返回值表示实际发生的事件数量。如果发生错误,将打印错误信息并退出程序。
  10. for (n = 0; n < nfds; ++n):遍历所有发生的事件。
  11. if (events[n].data.fd == listen_sock):判断事件是否与监听套接字相关联。如果是,表示有新的连接请求。
  12. conn_sock = accept(listen_sock, (struct sockaddr *) &local, &addrlen);:接受新的连接请求,并将新连接的套接字赋值给conn_sock。如果接受失败,将打印错误信息并退出程序。
  13. setnonblocking(conn_sock);:将新连接的套接字设置为非阻塞模式,以便后续处理。
  14. ev.events = EPOLLIN | EPOLLET;:设置事件类型为可读事件(EPOLLIN),并启用边缘触发(EPOLLET)。
  15. ev.data.fd = conn_sock;:将新连接的套接字的文件描述符设置为事件的关联数据。
  16. if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1):将新连接的套接字添加到epoll实例中,以便后续处理。如果添加失败,将打印错误信息并退出程序。
  17. else:如果事件与监听套接字无关,表示是一个已连接的客户端发送的数据。调用do_use_fd函数进行处理。

相关文章:

Redis的实现二: c、c++的网络通信编程技术,让服务器处理多个client

看过上期的都知道&#xff0c;我是搞java的&#xff0c;所以对这些可能理解不是很清楚&#xff0c;各位看完可以尽情发言。 事件循环和非阻塞IO 在服务器端网络编程中&#xff0c;有三种处理并发连接的方法。 它们是:分叉、多线程和事件循环。分叉为每个客户端连接创建新…...

QT上位机开发(动画效果)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 不管是仿真&#xff0c;还是对真实环境的一比一模拟&#xff0c;动画都是非常好的一种呈现方式。目前在qt上面&#xff0c;实现动画主要有两种方法…...

手写实现 bind 函数

Function.prototype.myBind function(context) {if (typeof this ! function) {return}const args [...arguments].slice(1)const fn thisreturn function Fn() {// 判断函数作为构造函数的情况&#xff0c;这个时候需要传入当前的函数的this给apply调用&#xff0c;其余情况…...

安卓Android Studio读写MifareOne M1 IC卡源码

本示例使用的发卡器&#xff1a;https://item.taobao.com/item.htm?id615391857885&spma1z10.5-c-s.w4002-21818769070.11.3d2f789eOUPJBK <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xm…...

一二三应用开发平台文件处理设计与实现系列之5——MinIO技术预研

背景 上篇介绍了文件读写框架设计与实现&#xff0c;同时顺便说明了本地磁盘存储模式的实现模式。 今天来说下基于文件读写框架&#xff0c;如何集成对象存储组件minio&#xff0c;集成之前&#xff0c;需要对minio进行必要的了解&#xff0c;本篇是minio的技术预研。 minio简…...

Native.js是什么

Native.js 是一个开源项目&#xff0c;旨在通过 JavaScript 调用原生 Android API。它的目标是让 JavaScript 开发者能够使用 Android 原生 API&#xff0c;从而在不编写原生代码的情况下构建 Android 应用。 使用 Native.js&#xff0c;开发者可以使用 JavaScript 调用 Andro…...

Vant-ui图片懒加载

核心代码 在你的全局顶部引入和初始化 Vue.use(vant.Lazyload, {loading: /StaticFile/img/jiazai.jpg,error: /StaticFile/img/jiazai.jpg,lazyComponent: false, });//图片懒加载 <img v-lazy"https://img-blog.csdnimg.cn/direct/3d2c8a7e2c0040488a8128c3e381d58…...

创建EasyCodeMybatisCodeHelperPro模板文件用于将数据库表生成前端json文件

在intellij idea中&#xff0c;通过插件EasyCodeMybatisCodeHelperPro&#xff0c;从现有的模板文件中选择一个复制粘贴&#xff0c;然后稍为修改&#xff0c;即可得到一个合适的模板文件。 现在的前端&#xff0c;越来越像后端。TypeScript替代了JavaScript&#xff0c;引入了…...

华为端口安全常用3种方法配置案例

安全动态mac地址学习功能 [Huawei]int g0/0/01 interface GigabitEthernet0/0/1 port-security enable //开启安全 port-security max-mac-num 2 //最多为2个mac地址学习 port-security protect-action restrict //丢包带警告 port-security aging-time 1 //mac地址的老化时间…...

RH850P1X芯片学习笔记-Flash Memory

文章目录 FeaturesClock Supply Block DiagramFlash SizeMemory ConfigurationRegistersRegister Base AddressList of RegistersRegister Reset Condition 与Flash Memory相关的操作模式Functional OverviewOption BytesOPBT0 — Option Byte 0OPBT1 — Option Byte 1OPBT2 —…...

利用XSS漏洞打cookie

目录 1、为什么要打cookie&#xff1f; 2、怎样利用XSS来打cookie&#xff1f; 3、利用Bluelotus_xssReceiver平台来打cookie 4、利用beef-xss平台来打cookie 上一篇给大家介绍了xss漏洞的基础知识&#xff0c;在本篇章将会介绍和演示一下利用xss漏洞打cookie的演示&#x…...

用java写个redis工具类

下面是一个简单的Redis工具类的示例&#xff0c;使用Java语言编写&#xff1a; import redis.clients.jedis.Jedis;public class RedisUtils {private static Jedis jedis;public static void connect(String host, int port) {jedis new Jedis(host, port);}public static v…...

实现防抖函数

// 防抖就是&#xff0c;事件触发 delay 秒后再执行&#xff0c;如果有重新的触发&#xff0c;重新计时 function debounce(func, delay) {if(typeof func ! function) {return}let timer 0return function () {if (timer) {clearTimeout(timer)timer null}timer setTimeout…...

MetaGPT task1学习

基础知识学习了解&#xff1a; 安装环境&#xff1a; 获取MetaGPT 使用pip获取MetaGPT pip install -i https://pypi.tuna.tsinghua.edu.cn/simple metagpt0.5.2 配置MetaGPT 完成MetaGPT后&#xff0c;我们还需要完成一些配置才能开始使用这个强力的框架&#xff0c;包括配…...

关于量子计算机的设想

从CPU架构说起 CISCRISCNISCCCSC CISC是复杂指令集计算机&#xff0c;以x86为代表&#xff1b; RISC是精简指令集计算机&#xff0c;以ARM为代表&#xff1b; NISC是无指令集计算机&#xff0c;CCSC是核-电路分离计算机&#xff0c;这两个是本文要讨论的内容。 如果没有指令…...

序列模型(4)—— Scaling Laws

本文介绍 LLM 训练过程中重要的 Scaling Laws&#xff0c;这是一个经验规律&#xff0c;指出了固定训练成本&#xff08;总计算量FLOPs&#xff09; C C C 时&#xff0c;如何调配模型规模&#xff08;参数量&#xff09; N N N 和训练 Token 数据量 D D D&#xff0c;才能实现…...

【软件测试学习笔记1】测试基础

1.软件测试的定义 软件的定义&#xff1a;控制计算机硬件工作的工具 软件的基本组成&#xff1a;页面客户端&#xff0c;代码服务器&#xff0c;数据服务器 软件产生的过程&#xff1a;需求产生&#xff08;产品经理&#xff09;&#xff0c;需求文档&#xff0c;设计效果图…...

pytorch详细探索各种cnn卷积神经网络

目录 torch.nn.functional子模块详解 conv1d 用法和用途 使用技巧 适用领域 参数 注意事项 示例代码 conv2d 用法和用途 使用技巧 适用领域 参数 注意事项 示例代码 conv3d 用法和用途 使用技巧 适用领域 参数 注意事项 示例代码 conv_transpose1d 用法…...

OpenCV——八邻域断点检测

目录 一、理论基础1、八邻域2、断点检测 二、代码实现三、结果展示四、参考链接 OpenCV——八邻域断点检测由CSDN点云侠原创&#xff0c;爬虫自重。如果你不是在点云侠的博客中看到该文章&#xff0c;那么此处便是不要脸的爬虫。 一、理论基础 1、八邻域 图1 八邻域示意图 图…...

leetcode238:除自身以外数组的乘积

文章目录 1.使用除法&#xff08;违背题意&#xff09;2.左右乘积列表3.空间复杂度为O(1)的方法 在leetcode上刷到了这一题&#xff0c;一开始并没有想到好的解题思路&#xff0c;写篇博客再来梳理一下吧。 题目要求&#xff1a; 不使用除法在O(n)时间复杂度内 1.使用除法&am…...

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻

在如今就业市场竞争日益激烈的背景下&#xff0c;越来越多的求职者将目光投向了日本及中日双语岗位。但是&#xff0c;一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧&#xff1f;面对生疏的日语交流环境&#xff0c;即便提前恶补了…...

Java 语言特性(面试系列2)

一、SQL 基础 1. 复杂查询 &#xff08;1&#xff09;连接查询&#xff08;JOIN&#xff09; 内连接&#xff08;INNER JOIN&#xff09;&#xff1a;返回两表匹配的记录。 SELECT e.name, d.dept_name FROM employees e INNER JOIN departments d ON e.dept_id d.dept_id; 左…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

CentOS下的分布式内存计算Spark环境部署

一、Spark 核心架构与应用场景 1.1 分布式计算引擎的核心优势 Spark 是基于内存的分布式计算框架&#xff0c;相比 MapReduce 具有以下核心优势&#xff1a; 内存计算&#xff1a;数据可常驻内存&#xff0c;迭代计算性能提升 10-100 倍&#xff08;文档段落&#xff1a;3-79…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils&#xff1a; ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类&#xff0c;封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz&#xff0c;先构建任务的 JobD…...

基础测试工具使用经验

背景 vtune&#xff0c;perf, nsight system等基础测试工具&#xff0c;都是用过的&#xff0c;但是没有记录&#xff0c;都逐渐忘了。所以写这篇博客总结记录一下&#xff0c;只要以后发现新的用法&#xff0c;就记得来编辑补充一下 perf 比较基础的用法&#xff1a; 先改这…...

在Ubuntu中设置开机自动运行(sudo)指令的指南

在Ubuntu系统中&#xff0c;有时需要在系统启动时自动执行某些命令&#xff0c;特别是需要 sudo权限的指令。为了实现这一功能&#xff0c;可以使用多种方法&#xff0c;包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法&#xff0c;并提供…...

css的定位(position)详解:相对定位 绝对定位 固定定位

在 CSS 中&#xff0c;元素的定位通过 position 属性控制&#xff0c;共有 5 种定位模式&#xff1a;static&#xff08;静态定位&#xff09;、relative&#xff08;相对定位&#xff09;、absolute&#xff08;绝对定位&#xff09;、fixed&#xff08;固定定位&#xff09;和…...