当前位置: 首页 > 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…...

CasRel模型LaTeX学术论文辅助工具:自动提取相关工作和贡献

CasRel模型LaTeX学术论文辅助工具&#xff1a;自动提取相关工作和贡献 每次打开一篇新的学术论文&#xff0c;尤其是那些动辄几十页的综述或顶会文章&#xff0c;你是不是也有点头大&#xff1f;密密麻麻的文字里&#xff0c;最关键的信息——“别人做了什么”、“他们有什么不…...

PETRV2-BEV模型的高精度3D车道检测效果展示

PETRV2-BEV模型的高精度3D车道检测效果展示 1. 引言 想象一下&#xff0c;一辆自动驾驶汽车在复杂的城市道路中行驶&#xff0c;需要实时识别车道线、判断可行驶区域、预测周围车辆轨迹。这背后离不开一项关键技术——3D车道检测。传统的2D检测方法在复杂道路场景中往往力不从…...

UniHacker:Unity引擎功能探索的技术研究指南

UniHacker&#xff1a;Unity引擎功能探索的技术研究指南 【免费下载链接】UniHacker 为Windows、MacOS、Linux和Docker修补所有版本的Unity3D和UnityHub 项目地址: https://gitcode.com/GitHub_Trending/un/UniHacker 技术研究免责声明 本指南所述工具及方法仅用于技术…...

ARM嵌入式开发:寄存器操作与函数指针实战

## 1. 嵌入式开发中的寄存器操作技巧### 1.1 寄存器地址访问方法 在ARM架构嵌入式开发中&#xff0c;直接操作硬件寄存器是底层开发的核心技能。通过C语言访问特定内存地址的标准做法是使用指针类型转换&#xff1a;c #define GSTATUS1 (*(volatile unsigned int *)0x560000B0)…...

保姆级教程:用Cloudreve+Obsidian打造私人云笔记(附WebDAV配置避坑指南)

零基础构建私有知识库&#xff1a;Cloudreve与Obsidian的完美联姻 在信息爆炸的时代&#xff0c;如何高效管理个人知识资产已成为现代人的刚需。想象一下&#xff1a;你正在咖啡馆用iPad记录灵感&#xff0c;回到家打开电脑时这些想法已自动同步&#xff1b;出差途中用手机查阅…...

FireRed-OCR保姆级教程:一键部署,精准提取表格公式转Markdown

FireRed-OCR保姆级教程&#xff1a;一键部署&#xff0c;精准提取表格公式转Markdown 1. 引言&#xff1a;为什么选择FireRed-OCR&#xff1f; 在日常工作和学习中&#xff0c;我们经常遇到需要从PDF、图片等文档中提取表格、公式等内容的情况。传统OCR工具往往难以准确识别复…...

SeqGPT-560M惊艳效果:支持多值字段提取——同一段文本中识别全部手机号而非仅首个

SeqGPT-560M惊艳效果&#xff1a;支持多值字段提取——同一段文本中识别全部手机号而非仅首个 在信息爆炸的时代&#xff0c;我们每天都要处理海量的非结构化文本。无论是从一份简历里找出候选人的所有联系方式&#xff0c;还是从一份合同里提取所有涉及的金额和日期&#xff…...

Node.js 环境避坑指南:从零搞定 Fetch MCP 依赖安装与构建 (Windows/macOS)

Node.js 环境避坑指南&#xff1a;从零搞定 Fetch MCP 依赖安装与构建 在开发者的日常工作中&#xff0c;遇到环境配置问题就像程序员遇到bug一样常见。特别是对于刚接触Node.js生态的前端新手&#xff0c;或是需要在不同操作系统间切换的开发者来说&#xff0c;一个看似简单的…...

【SpringBoot 】dynamic 动态数据源配置连接池(转)

前言 在复杂的业务场景中&#xff0c;我们经常需要使用多数据源来满足不同的数据访问需求。Dynamic Datasource 为我们提供了一种灵活切换不同数据源的解决方案。但是多数据源配置连接池 以及说明文档都是收费的。 本篇博文将详细介绍如何配置和优化 Dynamic Datasource 的连接…...

SVG-Edit:开源矢量编辑在浏览器工具中的创新实践

SVG-Edit&#xff1a;开源矢量编辑在浏览器工具中的创新实践 【免费下载链接】svgedit Powerful SVG-Editor for your browser 项目地址: https://gitcode.com/gh_mirrors/sv/svgedit SVG-Edit是一款基于浏览器环境的开源矢量图形编辑工具&#xff0c;提供在线SVG编辑能…...