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

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

React第五十七节 Router中RouterProvider使用详解及注意事项

前言 在 React Router v6.4 中&#xff0c;RouterProvider 是一个核心组件&#xff0c;用于提供基于数据路由&#xff08;data routers&#xff09;的新型路由方案。 它替代了传统的 <BrowserRouter>&#xff0c;支持更强大的数据加载和操作功能&#xff08;如 loader 和…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)

概述 在 Swift 开发语言中&#xff0c;各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过&#xff0c;在涉及到多个子类派生于基类进行多态模拟的场景下&#xff0c;…...

postgresql|数据库|只读用户的创建和删除(备忘)

CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...

cf2117E

原题链接&#xff1a;https://codeforces.com/contest/2117/problem/E 题目背景&#xff1a; 给定两个数组a,b&#xff0c;可以执行多次以下操作&#xff1a;选择 i (1 < i < n - 1)&#xff0c;并设置 或&#xff0c;也可以在执行上述操作前执行一次删除任意 和 。求…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

ABAP设计模式之---“简单设计原则(Simple Design)”

“Simple Design”&#xff08;简单设计&#xff09;是软件开发中的一个重要理念&#xff0c;倡导以最简单的方式实现软件功能&#xff0c;以确保代码清晰易懂、易维护&#xff0c;并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计&#xff0c;遵循“让事情保…...

深度学习习题2

1.如果增加神经网络的宽度&#xff0c;精确度会增加到一个特定阈值后&#xff0c;便开始降低。造成这一现象的可能原因是什么&#xff1f; A、即使增加卷积核的数量&#xff0c;只有少部分的核会被用作预测 B、当卷积核数量增加时&#xff0c;神经网络的预测能力会降低 C、当卷…...