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)
all_fds是一个包含所有需要监控的文件描述符的列表。while True:是一个无限循环,它会一直运行,直到程序被外部中断。active_fds = poll(all_fds)调用poll函数,返回一个包含所有准备好进行I/O操作的文件描述符的列表。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:如果文件描述符是一个客户端连接,那么进入一个循环,直到工作完成为止。在这个循环中,调用do_something_to_client(fd)函数处理客户端的数据。def do_something_to_client(fd):定义了这个函数。if should_read_from(fd):如果应该从文件描述符读取数据,那么调用read_until_EAGAIN(fd)函数读取数据,然后调用process_incoming_data(data)函数处理数据。while should_write_to(fd):如果应该向文件描述符写入数据,那么调用write_until_EAGAIN(fd)函数写入数据。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机制来处理客户端连接请求。以下是代码的详细解析:
#define MAX_EVENTS 10:定义了一个宏常量MAX_EVENTS,表示最多可以处理的事件数量为10。struct epoll_event ev, events[MAX_EVENTS];:定义了一个结构体数组events,用于存储epoll事件。每个事件由一个epoll_event结构体表示。int listen_sock, conn_sock, nfds, epollfd;:定义了四个整型变量,分别表示监听套接字、新连接的套接字、返回的文件描述符数量和epoll实例的文件描述符。epollfd = epoll_create(10);:创建了一个epoll实例,最大文件描述符数量为10。如果创建失败,将打印错误信息并退出程序。ev.events = EPOLLIN;:设置事件类型为可读事件(EPOLLIN)。ev.data.fd = listen_sock;:将监听套接字的文件描述符设置为事件的关联数据。if (epoll_ctl(epollfd, EPOLL_CTL_ADD, listen_sock, &ev) == -1):将监听套接字添加到epoll实例中,以便接收新的连接请求。如果添加失败,将打印错误信息并退出程序。for (;;):无限循环,不断处理事件。nfds = epoll_wait(epollfd, events, MAX_EVENTS, -1);:调用epoll_wait函数等待事件发生。参数-1表示等待所有类型的事件。返回值表示实际发生的事件数量。如果发生错误,将打印错误信息并退出程序。for (n = 0; n < nfds; ++n):遍历所有发生的事件。if (events[n].data.fd == listen_sock):判断事件是否与监听套接字相关联。如果是,表示有新的连接请求。conn_sock = accept(listen_sock, (struct sockaddr *) &local, &addrlen);:接受新的连接请求,并将新连接的套接字赋值给conn_sock。如果接受失败,将打印错误信息并退出程序。setnonblocking(conn_sock);:将新连接的套接字设置为非阻塞模式,以便后续处理。ev.events = EPOLLIN | EPOLLET;:设置事件类型为可读事件(EPOLLIN),并启用边缘触发(EPOLLET)。ev.data.fd = conn_sock;:将新连接的套接字的文件描述符设置为事件的关联数据。if (epoll_ctl(epollfd, EPOLL_CTL_ADD, conn_sock, &ev) == -1):将新连接的套接字添加到epoll实例中,以便后续处理。如果添加失败,将打印错误信息并退出程序。else:如果事件与监听套接字无关,表示是一个已连接的客户端发送的数据。调用do_use_fd函数进行处理。
相关文章:
Redis的实现二: c、c++的网络通信编程技术,让服务器处理多个client
看过上期的都知道,我是搞java的,所以对这些可能理解不是很清楚,各位看完可以尽情发言。 事件循环和非阻塞IO 在服务器端网络编程中,有三种处理并发连接的方法。 它们是:分叉、多线程和事件循环。分叉为每个客户端连接创建新…...
QT上位机开发(动画效果)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 不管是仿真,还是对真实环境的一比一模拟,动画都是非常好的一种呈现方式。目前在qt上面,实现动画主要有两种方法…...
手写实现 bind 函数
Function.prototype.myBind function(context) {if (typeof this ! function) {return}const args [...arguments].slice(1)const fn thisreturn function Fn() {// 判断函数作为构造函数的情况,这个时候需要传入当前的函数的this给apply调用,其余情况…...
安卓Android Studio读写MifareOne M1 IC卡源码
本示例使用的发卡器: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技术预研
背景 上篇介绍了文件读写框架设计与实现,同时顺便说明了本地磁盘存储模式的实现模式。 今天来说下基于文件读写框架,如何集成对象存储组件minio,集成之前,需要对minio进行必要的了解,本篇是minio的技术预研。 minio简…...
Native.js是什么
Native.js 是一个开源项目,旨在通过 JavaScript 调用原生 Android API。它的目标是让 JavaScript 开发者能够使用 Android 原生 API,从而在不编写原生代码的情况下构建 Android 应用。 使用 Native.js,开发者可以使用 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中,通过插件EasyCodeMybatisCodeHelperPro,从现有的模板文件中选择一个复制粘贴,然后稍为修改,即可得到一个合适的模板文件。 现在的前端,越来越像后端。TypeScript替代了JavaScript,引入了…...
华为端口安全常用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? 2、怎样利用XSS来打cookie? 3、利用Bluelotus_xssReceiver平台来打cookie 4、利用beef-xss平台来打cookie 上一篇给大家介绍了xss漏洞的基础知识,在本篇章将会介绍和演示一下利用xss漏洞打cookie的演示&#x…...
用java写个redis工具类
下面是一个简单的Redis工具类的示例,使用Java语言编写: 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…...
实现防抖函数
// 防抖就是,事件触发 delay 秒后再执行,如果有重新的触发,重新计时 function debounce(func, delay) {if(typeof func ! function) {return}let timer 0return function () {if (timer) {clearTimeout(timer)timer null}timer setTimeout…...
MetaGPT task1学习
基础知识学习了解: 安装环境: 获取MetaGPT 使用pip获取MetaGPT pip install -i https://pypi.tuna.tsinghua.edu.cn/simple metagpt0.5.2 配置MetaGPT 完成MetaGPT后,我们还需要完成一些配置才能开始使用这个强力的框架,包括配…...
关于量子计算机的设想
从CPU架构说起 CISCRISCNISCCCSC CISC是复杂指令集计算机,以x86为代表; RISC是精简指令集计算机,以ARM为代表; NISC是无指令集计算机,CCSC是核-电路分离计算机,这两个是本文要讨论的内容。 如果没有指令…...
序列模型(4)—— Scaling Laws
本文介绍 LLM 训练过程中重要的 Scaling Laws,这是一个经验规律,指出了固定训练成本(总计算量FLOPs) C C C 时,如何调配模型规模(参数量) N N N 和训练 Token 数据量 D D D,才能实现…...
【软件测试学习笔记1】测试基础
1.软件测试的定义 软件的定义:控制计算机硬件工作的工具 软件的基本组成:页面客户端,代码服务器,数据服务器 软件产生的过程:需求产生(产品经理),需求文档,设计效果图…...
pytorch详细探索各种cnn卷积神经网络
目录 torch.nn.functional子模块详解 conv1d 用法和用途 使用技巧 适用领域 参数 注意事项 示例代码 conv2d 用法和用途 使用技巧 适用领域 参数 注意事项 示例代码 conv3d 用法和用途 使用技巧 适用领域 参数 注意事项 示例代码 conv_transpose1d 用法…...
OpenCV——八邻域断点检测
目录 一、理论基础1、八邻域2、断点检测 二、代码实现三、结果展示四、参考链接 OpenCV——八邻域断点检测由CSDN点云侠原创,爬虫自重。如果你不是在点云侠的博客中看到该文章,那么此处便是不要脸的爬虫。 一、理论基础 1、八邻域 图1 八邻域示意图 图…...
leetcode238:除自身以外数组的乘积
文章目录 1.使用除法(违背题意)2.左右乘积列表3.空间复杂度为O(1)的方法 在leetcode上刷到了这一题,一开始并没有想到好的解题思路,写篇博客再来梳理一下吧。 题目要求: 不使用除法在O(n)时间复杂度内 1.使用除法&am…...
基于算法竞赛的c++编程(28)结构体的进阶应用
结构体的嵌套与复杂数据组织 在C中,结构体可以嵌套使用,形成更复杂的数据结构。例如,可以通过嵌套结构体描述多层级数据关系: struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...
React第五十七节 Router中RouterProvider使用详解及注意事项
前言 在 React Router v6.4 中,RouterProvider 是一个核心组件,用于提供基于数据路由(data routers)的新型路由方案。 它替代了传统的 <BrowserRouter>,支持更强大的数据加载和操作功能(如 loader 和…...
Java如何权衡是使用无序的数组还是有序的数组
在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
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
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
