Linux網絡編程:TCP的遠程多線程命令執行

目錄

?

前言:

一、前文補充

二、服務端的修改

三、Command類的新增


?

前言:

好久不見,最近忙于其他事情,就耽誤了咱們的Linux的網絡部分的學習。

今天咱們先來給之前所學的TCP的部分進行一個首尾工作,主要是給大家介紹一些函數與補充一下知識點。

那么今天我們將要實現的這個將會是什么功能呢?我們預期的就是大家遠程通過客戶端連接上服務端后,可以在服務端輸入一些命令,讓我們的服務端進行執行。

一、前文補充

前面我們已經通過多線程,多進程,線程池的方式分別實現了一個我們的TCP的EchoServer,今天我們先借著之前的代碼來繼續學習。

我們之前在進行TCP的數據的讀取寫入的時候,用到的函數是大家之前見過的write與read函數。其實我們這里之所以用到他們,主要是為了幫助大家理解我們通過accept返回的文件描述符。

但實際上我們的還可以使用另外一套接口,來進行數據的傳輸與傳入。

首先就是recv:

這個函數的第一個參數一樣是一個文件描述符,第二個參數要求我們提供一個用來接收消息的緩沖區,第三個參數是這個緩沖區的大小,第四個參數咱們先暫時不用管,直接填0就可以了。

所以我們的read函數就可以變成:

 int n = ::recv(sockfd,buffer,sizeof(buffer)-1,0);

0表示默認行為,即阻塞等待消息。這里使用sizeof(buffer)-1一樣是為了手動最后添上字符串終止符?\0

與之對應的,在客戶端的寫入消息,就可以使用send:

 int n = ::send(_sockfd, message.c_str(), message.size(), 0);

值得注意的是,不管是我們在這里使用read write還是send recv。其都是一個讀取/寫入不完善的操作。

為什么這樣說呢?

可能要到下節序列化我才能詳細給大家說明。

但是這個不完善是因為TCP的特點。還記得嗎,TCP是面向字節流,UDP是面向數據報。

對于我們的UDP來說,每次傳輸數據都是把所有數據傳輸過去,而面向字節流不同。

假如我們今天要給你發送一個 hello world,那么我們一定會完整接受到hello world嗎?

這是不一定的,說不定我們只會先接受到hello。更詳細的內容我們會在后面進行講解。

那么下面開始我們的今天的正題,如何給我們的服務端添加上執行命令的這些功能。


二、服務端的修改

首先,我們需要明確。在我們的服務端,仍然是通過之前寫的一個回調函數HandlerRequest來讓每一個線程執行。

我們想要降低耦合性,讓這個執行命令的功能不于我們的服務端文件雜糅在一起,所以我們可以先另起一個頭文件。通過之前的方式,創建一個執行命令的對象,然后在服務端類初始化時,通過lambda表達式傳進來一個回調函數。

所以我們需要在服務端的類成員變量中新增一個變量用來回調。

那我們先規定傳進來的lambda表達式的類型。

所以我們就先定義一個類型名為:

using handler_t=std::function<std::string (std::string)>;

隨后新增該類型的類成員變量:

 TcpServer(handler_t handler ,uint16_t port = defaultport): _port(port),is_running(false),_handler(handler){}......private:handler_t _handler;//回調函數執行命令調用的接口

在外界創建的時候就傳入一個lambda,如同這樣:


int main()
{Command cmd;std::unique_ptr<TcpServer> tcp_ptr=std::make_unique<TcpServer>([&cmd](std::string cmdstr){return cmd.Execute(cmdstr);});tcp_ptr->InitServer();tcp_ptr->Start();return 0;
}

這個方法之前我們已經使用過很多次了。所以這里就加快速度。

那么要繼續實現的就是我們的這個Command類的成員方法了,如何實現呢?

三、Command類的新增

現在我們開始實現一下我們的Command類:

首先就是類成員變量,我們可以設置一個白名單或者黑名單,就是限制一下那些命令我們可以使用,哪些命令我們不能使用。

我們這里就使用白名單的思維,在成員變量中實用set,只要在我們的set里,就是可以使用的。

隨后,在我們的構造函數中,添加一下可以使用的命令集,并增加一個判斷是否在我們的白名單的bool函數SafeCheck:

#pragma once
#include<string>
#include <set>class Command
{
public:Command(){_white_list.insert("ls");_white_list.insert("pwd");_white_list.insert("ls -l");_white_list.insert("ll");_white_list.insert("touch");_white_list.insert("who");_white_list.insert("whoami");}bool SafeCheck(const std::string &cmdstr){auto iter = _white_list.find(cmdstr);return iter == _white_list.end() ? false : true;}std::string Execute(std::string cmdstr){}private:std::set<std::string> _white_list;
};

這樣我們只需要在實現一下我們的執行命令的函數。

那么我們怎么執行呢?

我們之前是不是寫過SHell,把我們之前寫SHell的邏輯拿過來可以嗎?

肯定是可以的。但是我們都學了這么久了,還使用我們之前的方法未免不是很好,今天給大家介紹兩個函數:

popen 函數FILE *popen(const char *command, const char *mode);

這個popen函數他是什么功能呢?

:創建一個管道,fork一個子進程,并調用shell執行指定的命令

他有兩個參數,第一個參數就是傳進去的命令字符串,第二個參數就是模式,"r"表示從命令的?標準輸出?讀取數據,若為?"w"?則可向命令的標準輸入寫入。

沒錯,這個功能直接把我們以前所需要的做的工作全部都做了,集成到了這一個函數里。

他會返回一個文件流指針,我們可以通過這個文件流指針讀取信息。

具體操作如下:

        if (!SafeCheck(cmdstr)){return std::string(cmdstr + " 不支持");}FILE *fp = ::popen(cmdstr.c_str(), "r");if (nullptr == fp){return std::string("Failed");}char buffer[1024];std::string result;while (true){char *ret = ::fgets(buffer, sizeof(buffer), fp);if (!ret)break;result += ret;}

像我們輸入什么whoani這種命令都是有個打印效果的,我們此時就能通過fgets來獲取,并返回。

最后,與之對應的,我們會有pclose這個函數,負責關閉這個管道流,并等待子進程結束。

#pragma once
#include<string>
#include <set>class Command
{
public:Command(){_white_list.insert("ls");_white_list.insert("pwd");_white_list.insert("ls -l");_white_list.insert("ll");_white_list.insert("touch");_white_list.insert("who");_white_list.insert("whoami");}bool SafeCheck(const std::string &cmdstr){auto iter = _white_list.find(cmdstr);return iter == _white_list.end() ? false : true;}std::string Execute(std::string cmdstr){if (!SafeCheck(cmdstr)){return std::string(cmdstr + " 不支持");}FILE *fp = ::popen(cmdstr.c_str(), "r");if (nullptr == fp){return std::string("Failed");}char buffer[1024];std::string result;while (true){char *ret = ::fgets(buffer, sizeof(buffer), fp);if (!ret)break;result += ret;}pclose(fp);return result.empty() ? std::string("Done") : result;}private:std::set<std::string> _white_list;
};

注意,我們還要在服務端類中手動調用回調函數并獲取返回值:

         int n = ::recv(sockfd, buffer, sizeof(buffer) - 1, 0);if (n > 0){buffer[n] = 0; // 手動置入一個結束標記// std::string echo_str = "server echo$";// echo_str += buffer;std::string cmd_result = _handler(buffer);::send(sockfd, cmd_result.c_str(), cmd_result.size(), 0);}

最后我們編譯運行:

?

?

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

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

相關文章

重學React(三):狀態管理

背景&#xff1a; 繼續跟著官網的流程往后學&#xff0c;之前已經整理了描述UI以及添加交互兩個模塊&#xff0c;總體來說還是收獲不小的&#xff0c;至少我一個表面上用了四五年React的前端小卡拉米對React的使用都有了新的認知。接下來就到了狀態管理&#xff08;React特地加…

java web項目入門了解

目錄一、項目流程1. 使用servle2. 使用框架二、了解java web項目構造1. 項目目錄結構2. 查看頁面訪問順序3. 發起請求&#xff1a;jqueryajax4. 接受參數5. JSONJSON 數組三、get和post請求區別一、項目流程 1. 使用servle 有客戶端和服務端&#xff0c;客戶端和服務端進行交…

網絡資源模板--基于Android Studio 實現的日記本App

目錄 一、測試環境說明 二、項目簡介 三、項目演示 四、部設計詳情&#xff08;部分) 創建修改頁面 五、項目源碼 一、測試環境說明 電腦環境 Windows 11 編寫語言 JAVA 開發軟件 Android Studio (2020) 開發軟件只要大于等于測試版本即可(近幾年官網直接下載也可…

GO的啟動流程(GMP模型/內存)

目錄第一部分&#xff1a;程序編譯第二部分&#xff1a;函數解讀1&#xff09;Golang 核心初始化過程2&#xff09;創建第一個協程3&#xff09;啟動系統調度4&#xff09;跳轉main函數5&#xff09;總結第三部分&#xff1a;GMP模型Goroutine流程解讀第四部分&#xff1a;內存…

OLTP與OLAP:實時處理與深度分析的較量

OLTP&#xff08;Online Transaction Processing&#xff09;定義&#xff1a;OLTP 系統主要用于管理事務性應用程序的數據。這類系統需要支持大量的短時、快速的交互式事務&#xff0c;比如銀行交易、在線購物訂單等。特點&#xff1a;實時處理&#xff1a;OLTP 系統要求對數據…

數據安全與隱私保護:企業級防護策略與技術實現

引言&#xff1a;數據安全的新時代挑戰在數字化轉型加速的今天&#xff0c;數據已成為企業最核心的資產。然而&#xff0c;數據泄露事件頻發&#xff0c;據 IBM《2024 年數據泄露成本報告》顯示&#xff0c;全球數據泄露平均成本已達445 萬美元&#xff0c;較 2020 年增長了 15…

AI_RAG

一.為什么需要RAG&#xff08;AI幻覺&#xff09;大模型LLM在某些情況下給出的回答很可能錯誤的&#xff0c;涉及虛構甚至是故意欺騙的信息。二.什么是RAGRAG是一種結合“信息檢索”和“文本生成”的技術&#xff0c;旨在提升生成式AI模型的準確性和可靠性。它通過以下兩個核心…

LeetCode111~130題解

LeetCode111.二叉樹的最小深度&#xff1a; 題目描述&#xff1a; 給定一個二叉樹&#xff0c;找出其最小深度。 最小深度是從根節點到最近葉子節點的最短路徑上的節點數量。 說明&#xff1a;葉子節點是指沒有子節點的節點。 示例 1&#xff1a; 輸入&#xff1a;root …

n8n飛書webhook配置(飛書機器人、飛書bot、feishu bot)Crypto節點、js timestamp代碼、Crypto node

自定義機器人使用指南 利用 n8n 打造飛書 RSS 推送機器人 文章目錄自定義機器人使用指南注意事項功能介紹在群組中添加自定義機器人操作步驟邀請自定義機器人進群。- 進入目標群組&#xff0c;在群組右上角點擊更多按鈕&#xff0c;并點擊 設置。- 在右側 設置 界面&#xff0…

nhdeep檔案管理工具軟件官網

歡迎訪問nhdeep官網&#xff1a; www.nhdeep.com NHDEEP提供一系列專業的單機版檔案管理工具&#xff0c;滿足不同場景下的檔案管理需求&#xff0c;無需網絡連接&#xff0c;數據安全可靠。所有工具均提供免費試用版下載。 檔案綜合管理系統單機版:全面的檔案管理解決方案&a…

RocketMQ節點部署計算方案

節點計算公式 業務場景 預期峰值TPS&#xff1a;200,000 單組容量&#xff1a;40K TPS 容災要求&#xff1a;同城雙機房 nameServer節點數max(3, (15/50) 1) max(3, 0.3 1) max(3, 1.3) 3 Broker節點數ceil(200,000 / 40,000) 5組 總節點數 NameServer節點Broker組數(Mas…

MyBatis聯合查詢 - XML篇

文章目錄數據庫設計MyBatis 配置MyBatis 映射文件Mapper 接口總結數據庫設計 建表 SQL CREATE TABLE user (id INT PRIMARY KEY AUTO_INCREMENT,name VARCHAR(50) NOT NULL );CREATE TABLE order (id INT PRIMARY KEY AUTO_INCREMENT,user_id INT NOT NULL,order_no VARCHAR(…

Kubelet 探針如何選擇 IP:status.PodIP 溯源與“同 Pod 兩個 IP“現象解析

背景與現象同一個 Pod 的 readiness 和 liveness 探針日志顯示連接的 IP 不一致&#xff08;例如 10.10.6.10:9999 與 10.10.6.32:9999&#xff09;。本文從 kubelet 源碼入手&#xff0c;解釋探針目標 IP 的來源、為何會出現兩個不同 IP&#xff0c;并給出建議與驗證方法。在如…

Arm Development Studio 安全通告:CVE-2025-7427

安全之安全(security)博客目錄導讀 目錄 一、概述 二、CVE 詳情 三、受影響產品 四、建議 五、致謝 六、版本歷史 一、概述 ARM已知悉一個影響 Arm Development Studio 的安全漏洞&#xff0c;該漏洞可能允許攻擊者執行 DLL 劫持攻擊&#xff08;DLL hijacking attack&…

C#異步編程雙利器:異步Lambda與BackgroundWorker實戰解析

**摘要&#xff1a;**深入剖析兩種異步編程范式&#xff0c;解決GUI線程阻塞難題 一、異步Lambda表達式&#xff1a;事件處理的輕量化利器 核心價值&#xff1a;簡化事件響應中的異步操作&#xff0c;避免UI線程阻塞 ? 典型應用場景&#xff08;WPF示例&#xff09;&#xff1…

yolo world (1): 論文解讀

YOLO 系列檢測器以其高效性和實用性而聞名。然而,它們依賴于預定義和訓練的目標類別,這限制了其在開放場景中的適用性。為了解決這一限制,我們提出了 YOLO-World,這是一種創新的方法,通過視覺-語言建模和大規模數據集預訓練,增強了 YOLO 的開放詞匯檢測能力。具體來說,我…

【JVM】深入解析Java虛擬機

目錄 1. 區分JDK&#xff0c;JRE 和 JVM 1.1 JVM 1.2 JRE 1.3 JDK 1.4 關系總結 2. 跨平臺性 3. JVM中的內存劃分 4. JVM的類加載機制 5. 雙親委派模型 6. 垃圾回收機制&#xff08;GC&#xff09; 6.1 識別垃圾 6.1.1 單個引用 6.1.2 多個引用 6.2 釋放垃圾 6.…

98-基于Python的網上廚房美食推薦系統

基于Python的網上廚房美食推薦系統 - 技術分享博客 &#x1f4cb; 目錄 項目概述技術棧系統架構核心功能實現數據庫設計推薦算法數據可視化部署與優化項目特色總結與展望 &#x1f3af; 項目概述 項目背景 隨著生活節奏的加快&#xff0c;越來越多的人開始關注美食制作&…

創建MyBatis-Plus版的后端查詢項目

記得編碼和maven庫的檢測&#xff01;&#xff01;&#xff01; 1、maven庫導入包<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupI…

開發板RK3568和stm32的異同:

RK3568 和 STM32 是兩類不同定位的處理器 / 微控制器&#xff0c;在架構、性能、應用場景等方面差異顯著&#xff0c;但也存在部分共性。以下從核心特性、異同點及典型場景進行對比&#xff1a;一、核心差異維度RK3568&#xff08;瑞芯微&#xff09;STM32&#xff08;意法半導…