C++ socket epoll IO多路復用

IO多路復用通常用于處理單進程高并發,在Linux中,一切皆文件,一個socket連接會對應一個文件描述符,在監聽多個文件描述符的狀態應用中epoll相對于select和poll效率更高

epoll本質是系統在內核維護了一顆紅黑樹,監聽的文件描述符會作為新的節點插入紅黑樹,epoll會等待有狀態變化的節點記錄在鏈表里,然后拷貝到用戶所給的數組里面返回出來

以下是一個獨立的服務端代碼,可以補充業務代碼進行具體使用

sever.h

//
// Created by YEZI on 2024/5/24.
//#ifndef SEVER_H
#define SEVER_H
#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/epoll.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sstream>
#define MAX_EVENTS 8
#define PORT 8888
#define BUFFER_SIZE 512
#define BACKLOG_SIZE 16 // 請求隊列最大長度class Sever {
private:uint16_t port;int server_fd = -1;int epoll_fd = -1;sockaddr_in server_addr{}, client_addr{};socklen_t client_addr_len = sizeof(client_addr);epoll_event event{}, events[MAX_EVENTS]{};public:explicit Sever(uint16_t port = PORT): port(port) {// 創建套接字// AF_INET :   表示使用 IPv4 地址		可選參數// SOCK_STREAM 表示使用面向連接的數據傳輸方式,// IPPROTO_TCP 表示使用 TCP 協議server_fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);if (server_fd == -1) {std::cerr << "Failed to create socket\n";exit(EXIT_FAILURE);}// 設置服務器地址server_addr.sin_family = AF_INET; // IPv4server_addr.sin_addr.s_addr = INADDR_ANY; // INADDR_ANY:0.0.0.0 表示本機所有IP地址server_addr.sin_port = htons(PORT);// 綁定套接字if (bind(server_fd, (sockaddr *) &server_addr, sizeof(server_addr)) == -1) {std::cerr << "Failed to bind socket\n";exit(EXIT_FAILURE);}// 監聽套接字if (listen(server_fd, BACKLOG_SIZE) == -1) {std::cerr << "Failed to listen on socket\n";exit(EXIT_FAILURE);}// 創建 epoll 實例epoll_fd = epoll_create1(0); // flag設置為0同epoll_create()if (epoll_fd == -1) {std::cerr << "Failed to create epoll instance\n";exit(EXIT_FAILURE);}// 將服務器套接字添加到 epoll 實例中event.events = EPOLLIN | EPOLLET; // 監聽事件類型 EPOLLIN表示有數據可讀 EPOLLET表示邊緣觸發僅在狀態變化時通知event.data.fd = server_fd;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event) == -1) {std::cerr << "Failed to add server socket to epoll\n";exit(EXIT_FAILURE);}std::cout << "Server started. Listening on port " << PORT << "...\n";}void run() {while (true) {// 使用 epoll 等待事件 參數timeout為等待時間,-1等死int num_ready = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);if (num_ready == -1) {std::cerr << "Error in epoll_wait\n";exit(EXIT_FAILURE);}for (int i = 0; i < num_ready; ++i) {if (events[i].data.fd == server_fd) {// 有新的連接請求int client_fd = accept(server_fd, (sockaddr *) &client_addr, &client_addr_len);if (client_fd == -1) {std::cerr << "Failed to accept client connection\n";continue;}std::cout << "New connection from " << inet_ntoa(client_addr.sin_addr)<< ":" << ntohs(client_addr.sin_port) << std::endl;// 將新的客戶端套接字添加到 epoll 實例中event.events = EPOLLIN | EPOLLET;event.data.fd = client_fd;if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event) == -1) {std::cerr << "Failed to add client socket to epoll\n";exit(EXIT_FAILURE);}} else {// 有數據到達現有客戶端套接字char buffer[BUFFER_SIZE]{};ssize_t bytes_received = recv(events[i].data.fd, buffer, BUFFER_SIZE, 0);if (bytes_received <= 0) {if (bytes_received == 0) {// 客戶端關閉連接std::cout << "Client disconnected\n";} else {std::cerr << "Error in recv\n";}// 關閉客戶端套接字,并從 epoll 實例中移除close(events[i].data.fd);epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, nullptr);} else {// 接收到數據,原樣發送回客戶端,此處為業務代碼補充處send(events[i].data.fd, buffer, bytes_received, 0);std::istringstream iss(buffer);std::string data;while (iss >> data) {std::cout << data << ' ';}std::cout<<std::endl;}}}}}~Sever() {// 關閉服務器套接字和 epoll 實例close(server_fd);close(epoll_fd);}
};
#endif //SEVER_H

main.cpp

#include"sever.h"
int main() {Sever sever;sever.run();
}

簡單測試服務端,打開Linux終端,用一下命令連接服務器后即可傳輸數據

telnet localhost 8888

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/15338.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/15338.shtml
英文地址,請注明出處:http://en.pswp.cn/web/15338.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Linux中bash腳本怎么表示一個字符串變量

Linux中bash腳本怎么表示一個字符串變量 在Bash腳本中&#xff0c;你可以使用單引號&#xff08;&#xff09;或雙引號&#xff08;"&#xff09;來表示一個字符串變量。以下是兩種方式的示例&#xff1a; 使用單引號&#xff08;&#xff09;&#xff1a; my_variable…

flink 和 clipper搭配使用

Flink是一個用于流處理和批處理的開源框架&#xff0c;可以實時數據處理和分析。 Clipper 是一個用于機器學習模型服務化的開源框架&#xff0c;能夠輕松部署和管理機器學習模型&#xff0c;使模型可以通過統一的接口提供在線推理服務。 flink和clipper搭配使用&#xff1a; …

Leetcode | 5-21| 每日一題

2769. 找出最大的可達成數字 考點: 暴力 數學式子計算 思維 題解 通過式子推導: 第一想法是二分確定區間在區間內進行查找是否符合條件的, 本題最關鍵的便是 條件確定 , 第二種方法: 一般是通過數學公式推導的,這種題目我稱為數學式編程題 代碼 條件判斷式 class Solution { …

需求分析的任務

1 確定對系統的綜合要求 雖然功能需求是對軟件系統的一項基本需求&#xff0c;但卻并不是唯一的需求。通常對軟件系統有下述幾方面的綜合要求。 1&#xff0e;功能需求 這方面的需求指定系統必須提供的服務。通過需求分析應該劃分出系統必須完成的所有功能。 2&#xff0e;性能…

MacBook 怎么玩Windows游戲 蘋果筆記本怎么玩游戲?mac上如何玩windows游戲

傳統上&#xff0c;Mac 不被認為是好的游戲機。然而&#xff0c;蘋果已經開始在 Mac 上的游戲上投入更多精力&#xff0c;特別是自從轉向蘋果芯片以來。這使得 Mac 游戲的本機移植數量和模擬 Windows 游戲的能力都得到了顯著提高。 方法一&#xff1a;Boot Camp 1、Boot Camp是…

SpirngMVC框架學習筆記(一):SpringMVC基本介紹

1 SpringMVC 特點&概述 SpringMVC 從易用性&#xff0c;效率上 比曾經流行的 Struts2 更好 SpringMVC 是 WEB 層框架&#xff0c;接管了 Web 層組件, 比如控制器, 視圖, 視圖解析, 返回給用戶的數據格式, 同時支持 MVC 的開發模式/開發架構SpringMVC 通過注解&#xff0c;…

Java數據結構和算法(B樹)

前言 B樹又叫平衡的多路搜索樹&#xff1b;平衡的意思是又滿足平衡二叉樹的一些性質&#xff0c;左樹大于右樹&#xff1b; 多路意思是&#xff0c;可以多個結點&#xff0c;不再是像二叉樹只有兩個結點&#xff1b; 實現原理 B樹是一種自平衡的搜索樹&#xff0c;通常用于實…

MySQL和MongoDB數據庫的區別

MySQL和MongoDB數據庫的區別 隨著大數據和云計算技術的興起&#xff0c;數據庫的選擇成為開發者和架構師必須面對的重要決策。MySQL和MongoDB作為關系型數據庫和非關系型數據庫的代表&#xff0c;在各自領域都有著廣泛的應用。本文將從多方面詳細比較MySQL和MongoDB&#xff0…

MATLAB:插值函數之interp與griddata

MATLAB 提供了多種插值函數來處理不同維度的數據。其中&#xff0c;interp1、interp2 和 griddata 是常用的插值函數&#xff0c;分別用于一維、二維和多維&#xff08;不規則&#xff09;數據的插值。 之前有對interp1進行過詳細介紹&#xff0c;如需詳細了解&#xff0c;請查…

會聲會影調速怎么用 會聲會影如何調整音頻速度

會聲會影是一款功能強大的視頻編輯軟件&#xff0c;可以幫助我們輕松的實現剪輯。 會聲會影的操作簡單易懂&#xff0c;界面簡潔明快。適合家庭使用&#xff0c; 我們使用會聲會影可以在家就能將視頻剪輯成好萊塢大片。但是在使用的過程中&#xff0c;仍然會遇到一些操作上的問…

洛谷 P3803 【模板】多項式乘法(FFT)

【模板】多項式乘法&#xff08;FFT&#xff09; 題目背景 這是一道多項式乘法模板題。 注意&#xff1a;本題并不屬于中國計算機學會劃定的提高組知識點考察范圍。 題目描述 給定一個 n n n 次多項式 F ( x ) F(x) F(x)&#xff0c;和一個 m m m 次多項式 G ( x ) G(…

C語言--指針數組和數組指針的區別

指針數組 就是一個數組&#xff0c;由指針構成的數組&#xff0c;每一個元素都是指針&#xff0c;每個指針可以指向不同的內存地址&#xff0c;這些地址可以是數組、變量。 int var1 10; int var2 20; int var3 30;int *ptrArray[3]; // 定義一個指針數組&#xff0c;包含…

2024年上半年軟件系統架構師論文【回憶版】

文章目錄 考試時間考試地點案例分析1、微服務架構的優點和缺點2、質量屬性的6個元素3、分布式鎖 Redis的缺點4、MongoDB 存儲矢量圖的優勢 論文回憶版論文一、論單元測試的設計與應用論文二、論大數據模型的設計與應用論文三、論模型驅動的架構設計及應用論文四、論云原生運維的…

Mybatis-Plus-Join

1. 簡介 官網 https://mybatisplusjoin.com/ 2. 基本用法 步驟&#xff1a; 添加依賴 <!--mybatis-plus-join--> <dependency><groupId>com.github.yulichang</groupId><artifactId>mybatis-plus-join-boot-starter</artifactId><ve…

探索LangGraph:如何創建一個既智能又可控的航空客服AI

這種設計既保持了用戶控制權&#xff0c;又確保了對話流程的順暢。但隨著工具數量的增加&#xff0c;單一的圖結構可能會變得過于復雜。我們將在下一節中解決這個問題。 第三部分的圖將類似于下面的示意圖&#xff1a; 狀態定義 首先&#xff0c;定義圖的狀態。我們的狀態和L…

homography原理和圖像相似度計算

1. homography 講homography原理 講homography應用 2. 圖像相似度計算 20230621-計算兩幅圖像的相似度 20221205-有史以來最全的圖像相似度算法 20231112-圖像相似度對比方法

C++:List的使用和模擬實現

???學習的道路很枯燥&#xff0c;希望我們能并肩走下來! 文章目錄 目錄 文章目錄 前言 一 list的介紹及使用 1.1 list的介紹 1.2 list的使用 1.2.1 list的構造 1.2.2 list iterator的使用 1.2.3 list capacity 1.2.4 list element access 1.2.5 list modifiers …

golang+redis的延時隊列

網址 https://github.com/cfanbo/delay-queue-redis 代碼結構很簡單&#xff0c;簡單代表著自由度很高&#xff0c;使用過程中出現問題也很好修改。 我很喜歡這樣的代碼&#xff0c;至少我看的懂&#xff0c;該有的都有。 //package main // //import ( // "context&q…

leetcode209_長度最小的子數組

要求某個連續的區間內的元素值總和>S . 思路&#xff1a;滑動窗口&#xff1a;本質上是一種雙指針法。 &#xff08;1&#xff09;初始化left right 0&#xff1b; &#xff08;2&#xff09;left不動&#xff0c;right移動&#xff0c;擴大窗口&#xff0c;直至符合要…