Boost.Asio學習(2):同步讀寫

Asio 的 buffer 是什么?

boost::asio::buffer(...) 是一個函數模板,用于創建一個通用的 buffer 對象,可傳遞給 I/O 函數(如 read, write, read_some, write_some 等)。

它返回的是 mutable_bufferconst_buffer 的對象,取決于你傳入的參數是可寫還是只讀。

boost::asio::buffer(char* data, std::size_t size);      // 返回 mutable_buffer
boost::asio::buffer(const char* data, std::size_t size); // 返回 const_buffer
boost::asio::buffer(std::string&)   // mutable_buffer
boost::asio::buffer(const std::string&) // const_buffer
boost::asio::buffer(std::vector<char>&) // mutable_buffer

mutable_bufferconst_buffer 的區別

類型權限用途舉例場景
mutable_buffer可寫讀取數據(recv)read_some()async_read()
const_buffer只讀寫入數據(send)write_some()async_write()
  • mutable_buffer 只能傳給讀操作,如 socket.read_some()

  • const_buffer 只能傳給寫操作,如 socket.write_some()

buffer 支持多塊

可以將多個 buffer 組成一個 buffer sequence:

char part1[64], part2[64];
std::vector<boost::asio::mutable_buffer> bufs {boost::asio::buffer(part1),boost::asio::buffer(part2)
};
socket.read_some(bufs);

?buffer() 函數在調用時傳不傳 size 參數

char data[100];// ? 自動推導 size(推薦,謹慎)
auto buf1 = boost::asio::buffer(data); // size = 100// ? 手動指定 size(安全、精確)
auto buf2 = boost::asio::buffer(data, 64); // size = 64

示例 1:發送 buffer 超范圍

char data[100] = "hello";
auto buf1 = boost::asio::buffer(data);       // size = 100
auto buf2 = boost::asio::buffer(data, 5);    // size = 5socket.send(buf1); // ?? 發送了 100 字節,包含未初始化部分!
socket.send(buf2); // ? 只發送了 "hello"

示例 2:std::string 的問題

std::string str = "hello";
auto buf1 = boost::asio::buffer(str);              // size = 5
auto buf2 = boost::asio::buffer(str, str.size());  // 等價于 buf1
auto buf3 = boost::asio::buffer(str.c_str());      // size = strlen(c_str()) + 1(包含 \0)??
情況是否建議手動指定 size
發送部分數據? 推薦
結構體轉 buffer 時? 避免讀取未初始化區域
動態分配內存? 明確 buffer 長度
string、vector 直接用? 可不指定,自動使用 .size()
char*/void* 原始指針? 必須指定 size
數據來源buffer 用法推薦程度
std::stringbuffer(str)? 安全
std::vectorbuffer(vec)? 安全
char[100]buffer(arr)? 自動推導
char* ptrbuffer(ptr, length)? 必須指定
發送部分數據buffer(data, actual_data_size)? 強烈推薦

發送數據

(以下給出的函數原型與源碼不完全相同,只是作為大致用法的例子)

send

  • 屬于 socket成員函數

  • 調用底層 ::send() 系統調用;

  • 一次嘗試寫部分數據(可能寫不完);

  • 你要自己處理剩余數據;

// 拋異常版本
std::size_t send(const boost::asio::const_buffer& buffer);// 可加 flags(如 MSG_DONTWAIT)
std::size_t send(const boost::asio::const_buffer& buffer, socket_base::message_flags flags);std::size_t send(const boost::asio::const_buffer& buffer, socket_base::message_flags flags, boost::system::error_code& ec);

write_some

  • 同樣是 成員函數

  • 一次性嘗試寫 buffer 中盡量多的數據

  • 不保證寫滿;

  • 適合你 控制寫的粒度,或用于非阻塞模式;

// 拋異常版本
std::size_t write_some(const boost::asio::const_buffer& buffer);// 使用 error_code
std::size_t write_some(const boost::asio::const_buffer& buffer, boost::system::error_code& ec);

write

  • 全局函數模板

  • 會自動循環調用 write_some(),直到寫完整個 buffer;

  • 適合你想 一次性寫完所有數據 的情況;

位于 boost/asio/write.hpp,可用于任意 SyncWriteStream 類型(如 TCP socket):

// 單個 buffer,拋異常版本
template <typename SyncWriteStream, typename ConstBufferSequence>
std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers);// 單個 buffer,帶 error_code
template <typename SyncWriteStream, typename ConstBufferSequence>
std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, boost::system::error_code& ec);// 可指定 completion condition(寫多少算完)
template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition>
std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition);template <typename SyncWriteStream, typename ConstBufferSequence, typename CompletionCondition>
std::size_t write(SyncWriteStream& s, const ConstBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec);
特性send()write_some()write()
類型socket 的成員函數socket 的成員函數全局模板函數
發送完整數據?? 只發送部分(不保證)? 不保證? 會完整發送
底層系統調用直接 send()直接 send()調用 write_some() 多次
適合場景手動控制寫入過程高性能或非阻塞寫場景簡潔、完整性保證(推薦)
使用復雜度? 最簡單
支持 buffer sequence?? 單一 buffer? 單一 buffer? 可寫多 buffer(scatter I/O)
支持 flags(如 MSG_NOSIGNAL)? 可以傳 flags 參數(低層控制)? 不支持 flags

send()通用 socket 接口,適用于 TCP 和 UDP,底層等價于 BSD 的 send() 系統調用;而 write_some()流式 socket 的專用寫函數,更貼近 TCP 的流語義,不適用于 UDP。?

返回值

這三個函數的返回值都是 std::size_t 類型,表示“實際寫入/發送成功的字節數”,它們不會包含錯誤碼?

情況是否可能返回 0?說明
send()? 是Socket 被關閉,或對方關閉連接,或 buffer.size() == 0
write_some()? 是同上
write()? 不會內部循環,直到寫完或報錯為止,返回至少 1 或拋異常

Boost.Asio 中 send()write_some()write() 這三個函數的返回值永遠不會是負數。?

在傳統 POSIX socket 中,send()write() 返回的是 ssize_t:?

  • 如果出錯,返回 -1,并通過 errno 指出錯誤原因;

  • 這是 C 語言 API 的慣例。

Boost.Asio 的做法不同:

錯誤處理方式返回負數?錯誤表現方式
拋異常版本? 否拋出 boost::system::system_error 異常
error_code 版本? 否返回值為 0,錯誤通過 ec 指出

?接收數據

receive

這是底層 socket 的成員函數,可以接收部分數據,可用于 TCP 和 UDP。

// 拋異常版本
std::size_t receive(boost::asio::mutable_buffer buffer);// 帶 flags
std::size_t receive(boost::asio::mutable_buffer buffer, socket_base::message_flags flags);std::size_t receive(boost::asio::mutable_buffer buffer, socket_base::message_flags flags, boost::system::error_code& ec);

?read_some

這是 socket 的成員函數,僅用于 TCP(流式協議),功能類似于 recv(),但偏高層。

// 拋異常版本
std::size_t read_some(boost::asio::mutable_buffer buffer);// 使用 error_code
std::size_t read_some(boost::asio::mutable_buffer buffer, boost::system::error_code& ec);

read

這是 Boost.Asio 的全局函數模板,會自動循環調用 read_some(),直到讀完你想要的所有字節,適合完整讀取。

// 單個 buffer,拋異常版本
template <typename SyncReadStream, typename MutableBufferSequence>
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers);// 帶 error_code
template <typename SyncReadStream, typename MutableBufferSequence>
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, boost::system::error_code& ec);// 可指定完成條件
template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition>
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition);template <typename SyncReadStream, typename MutableBufferSequence, typename CompletionCondition>
std::size_t read(SyncReadStream& s, const MutableBufferSequence& buffers, CompletionCondition completion_condition, boost::system::error_code& ec);
特性receive()read_some()read()
類型socket 的成員函數stream socket 的成員函數全局模板函數
接收完整數據?? 只讀一部分? 不保證? 自動循環直到讀夠為止
底層系統調用直接調用 recv()直接調用 recv()內部多次調用 read_some()
支持協議? TCP + UDP? TCP(流)? TCP(SyncReadStream 概念)
支持 flags(如 MSG_PEEK? 支持? 不支持? 不支持
適合場景精細控制、非阻塞收包高性能讀入流數據? 最推薦完整讀取某個對象/幀
使用復雜度? 最簡單
支持 buffer sequence?? 不支持? 不支持? 支持 scatter buffer

返回值?

函數名返回值類型返回值含義
receive()std::size_t成功讀取的字節數(可能是部分)
read_some()std::size_t本次調用成功讀取的字節數
read()std::size_t多次調用累計讀取的總字節數(直到完成條件)
函數是否可能返回 0說明
receive()? 是socket 被關閉、對方斷開、buffer size 為 0
read_some()? 是同上
read()? 否會循環直到讀夠或拋異常,除非你指定了 completion 條件

?這三個函數?判斷對端關閉連接,要依靠 error_code,而不是返回值!

  • 可能返回 0:但返回 0 不一定意味著對方斷開

  • 真正的連接關閉,需要檢查 error_code

判斷對方關閉連接的唯一正確方式是:ec == boost::asio::error::eof。不要依賴返回值為 0。

正確的寫法(判斷連接關閉):

boost::system::error_code ec;
std::array<char, 1024> buf{};std::size_t len = socket.read_some(boost::asio::buffer(buf), ec);if (ec == boost::asio::error::eof) {std::cout << "對端已關閉連接(eof)" << std::endl;
} else if (ec) {std::cout << "其他錯誤: " << ec.message() << std::endl;
} else {std::cout << "收到數據: " << std::string(buf.data(), len) << std::endl;
}

成對用法

?send-receive

發送

// 準備要發送的數據
std::string msg = "hello";  // 不包含 \0,Asio 不自動加
msg.push_back('\0');        // 明確加上 \0(等價于你的 send_len = strlen+1)// 發送數據
boost::system::error_code ec;
std::size_t len = socket.send(asio::buffer(msg),0,ec);

?接收

// 接收數據
std::array<char, 100> recv_buf{};
boost::system::error_code ec;
std::size_t len = socket.receive(asio::buffer(recv_buf),0,ec);

write_some-read_some

發送

// 準備要發送的數據
std::string msg = "hello";  // 不包含 \0,Asio 不自動加
msg.push_back('\0');        // 明確加上 \0(等價于你的 send_len = strlen+1)// 發送數據
boost::system::error_code ec;
std::size_t len = socket.write_some(asio::buffer(msg),ec);

接收

// 接收數據
std::array<char, 100> recv_buf{};
boost::system::error_code ec;
std::size_t len = socket.read_some(asio::buffer(recv_buf),ec);

write-read

發送

// 準備要發送的數據
std::string msg = "hello";  // 不包含 \0,Asio 不自動加
msg.push_back('\0');        // 明確加上 \0(等價于你的 send_len = strlen+1)// 發送數據
boost::system::error_code ec;
std::size_t len = asio::write(socket, asio::buffer(msg), ec);

接收

// 接收數據
std::array<char, 100> recv_buf{};
boost::system::error_code ec;
//這里的buffer如果不指定,默認是100,但是我們沒發這么多
//如果不指定,它會一直等,但是我們另一端發完就把socket釋放了,于是這一端會出錯
std::size_t len = asio::read(socket, asio::buffer(recv_buf,6), ec);

阻塞與非阻塞

默認情況下(即你不手動設置非阻塞、也沒用異步函數)

Boost.Asio 中的 三類收發函數——send() / write_some() / write()recv() / read_some() / read()——都是阻塞的!

函數默認是否阻塞?阻塞直到...
socket.send()? 是至少部分數據寫入內核緩沖區或報錯
socket.write_some()? 是寫入一部分成功或出錯
asio::write()? 是全部 buffer 寫完或出錯(自動循環 write_some)
函數默認是否阻塞?阻塞直到...
socket.recv()? 是至少讀入一部分或出錯
socket.read_some()? 是一次性讀取當前內核中已有的數據或出錯
asio::read()? 是buffer 全部讀滿或出錯(自動循環 read_some)

非阻塞 = 函數立即返回,不等待系統緩沖區可用或數據可達

  • 如果不能立即完成,函數:

    • 拋出 boost::asio::error::would_block

    • 或返回 0 并設置 error_codewould_block

類型非阻塞行為立即返回?處理方式
send()? 支持
write_some()? 支持不能寫入全部就返回部分或拋錯
write()?? 不建議用于非阻塞? 否會循環調用 write_some 阻塞等待
recv()? 支持沒數據就拋 would_block
read_some()? 支持讀部分數據或拋 would_block
read()?? 不建議非阻塞使用? 否會阻塞直到 buffer 滿或報錯

如何設置非阻塞模式

socket.non_blocking(true);

flags

Boost.Asio 的 send()receive() 函數提供了 flags 參數,用來設置底層 BSD socket API 的行為?

在 Boost.Asio 中通過枚舉類:

boost::asio::socket_base::message_flags

一些標志 :

Boost.Asio 枚舉名底層等效宏含義說明
boost::asio::socket_base::message_peekMSG_PEEK查看數據但不消費
boost::asio::socket_base::message_out_of_bandMSG_OOB緊急數據(帶外)
boost::asio::socket_base::message_do_not_routeMSG_DONTROUTE不走路由表
boost::asio::socket_base::message_end_of_recordMSG_EOR表示數據為一條完整記錄(少用)

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

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

相關文章

Java中如何枚舉正則表達式捕獲組的名字

在使用正則表達式在匹配文本時&#xff0c;除了可以通過表達式捕獲命中的文本串外&#xff0c;還可以對捕獲的文本串進行命名。尤其是在解析日志的場景中&#xff0c;經常會被用到。表達式如下&#xff1a; \<(?<pri>\d)\>(?<time>.*) (?<host>\S)…

CentOS 系統高效部署 Dify 全攻略

系列文章目錄 CentOS系統高效部署fastGPT全攻略 文章目錄 系列文章目錄一、前言二、準備工作與系統要求三、安裝 Docker 與 Docker Compose四、部署 Dify 核心服務五、數據庫與存儲配置六、網絡與安全優化七、監控與運維八、升級與擴展九、附錄與資源關鍵命令速查表官方文檔…

xyctf2025第三屆京麒CTF

一.MISC 1.XGCTF 直接ai搜索一遍找到了出題人的博客LamentXU 2024-2025年終總結 - LamentXU - 博客園 知道了原題是ciscn中的 在LamentXU的博客亂逛Patriot CTF 2024 MISC 部分 wp - LamentXU - 博客園 找到了博客網站,讓后搜索ciscn扎到了博客 CISCN華東南WEB-Polluted |…

Python爬蟲 模擬登錄 requests版

前言 網站必須是登錄狀態才能查看網站信息,是最常見的反爬手段,下面我分享一下request模擬登錄狀態進行請求 目錄 模擬登錄的原理 直接復制網站Cookie模擬登錄狀態 通過登錄接口信息破解出Cookie模擬登錄狀態 模擬登錄的原理 網站是使用Cookie和session記錄網站的登錄狀態…

一些改進策略

1.要計算一個神經網絡模型的總參數量、可訓練參數量以及計算量&#xff08;FLOPs&#xff09;&#xff0c;可以使用以下步驟&#xff1a; ### 計算總參數量和可訓練參數量&#xff1a; 1. **逐層計算參數量**&#xff1a; - 對于每一層&#xff0c;確定該層的參數量。這通…

React Native響應式布局實戰:告別媒體查詢,擁抱跨屏適配新時代

前言:當設計師說"這個頁面要適配所有手機和平板…" “什么?React Native不支持CSS媒體查詢?那怎么實現響應式布局?”——這是很多剛接觸React Native的開發者會遇到的靈魂拷問。 但別慌,沒有@media,我們照樣能玩轉多端適配!想象一下:你的App在iPhone SE的小…

[Java惡補day39] 整理模板·考點六【反轉鏈表】

考點六【反轉鏈表】 【考點總結】 1. 206. 【題目】 【核心思路】 【復雜度】 時間復雜度&#xff1a; O ( ) O() O()。 空間復雜度&#xff1a; O ( ) O() O()。 【代碼】 92. 【題目】 【核心思路】 【復雜度】 時間復雜度&#xff1a; O ( ) O() O()。 空間復雜度&a…

7,TCP服務器

1,創建一個工程 文件目錄:

Modbus_TCP_V5 新功能

odbus TCP 服務器指令 MB_SERVER V5.0 新功能概述 如下圖1所示服務器指令 MB_SERVER 從 V5.0 以后增加了三個新功能&#xff0c;分別為&#xff1a; 訪問數據塊中的數據區域&#xff0c;而不是直接訪問 MODBUS 地址過程映像區的讀訪問限制統計變量 NDR_immediate 和 DR_immed…

2-RuoYi-UI管理平臺的啟動

RuoYi-UI是RuoYi后端框架的管理中心(基于 Vue.js 的前端項目)的詳細配置與啟動指南,結合官方文檔和常見實踐整理,涵蓋環境準備、配置修改、啟動流程及問題排查。 ?? 一、環境準備 Node.js 版本要求:≥12.0(推薦 ≥14.0 或 18.18+ 適配 Vue3) 安裝后驗證: node -v …

WPF學習筆記(21)ListBox、ListView與控件模板

ListBox與控件模板 一、 ListBox默認控件模板詳解二、ItemsPresenter集合數據呈現1. 概述2. 示例 三、 ListView默認控件模板詳解1. 概述2. 示例 一、 ListBox默認控件模板詳解 WPF 中的大多數控件都有默認的控件模板。 這些模板定義了控件的默認外觀和行為&#xff0c;包括控…

操作系統【2】【內存管理】【虛擬內存】【參考小林code】

本文完全參考 虛擬內存內存分段內存分頁段頁式內存管理Linux內存管理 一、虛擬內存 1. 單片機的絕對物理地址 以單片機作為引子&#xff0c;它沒有操作系統&#xff0c;每次寫完程序是借助工具將程序燒錄進單片機&#xff0c;程序才能運行。 單片機由于沒有操作系統&#…

【王樹森推薦系統】召回05:矩陣補充、最近鄰查找

概述 這節課和后面幾節課將詳細講述向量召回&#xff0c;矩陣補充是向量召回最簡單的一種方法&#xff0c;不過現在已經不太常用這種方法了本節課的矩陣補充是為了幫助理解下節課的雙塔模型上節課介紹了embedding&#xff0c;它可以把用戶ID和物品ID映射成向量 矩陣補充 模型…

C# 事件(訂閱事件和觸發事件)

訂閱事件 訂閱者向事件添加事件處理程序。對于一個要添加到事件的事件處理程序來說&#xff0c;它必須具有 與事件的委托相同的返回類型和簽名。 使用運算符來為事件添加事件處理程序&#xff0c;如下面的代碼所示。事件處理程序位于該運 算符的右邊。事件處理程序的規范可以…

64頁精品PPT | 基于DeepSeek的數據治理方案AI大數據治理解決方案數據治理大模型解決方案

這份PPT文檔是關于基于DeepSeek的大模型技術在數據治理方案中的應用介紹。強調數據作為新型生產要素與人工智能技術相結合的重要性&#xff0c;指出大模型憑借強大的文學理解、生成能力以及多模態數據處理能力&#xff0c;能為數據治理帶來新機遇。文檔詳細闡述了數據資產化的路…

【文獻筆記】Tree of Thoughts: Deliberate Problem Solving with Large Language Models

Tree of Thoughts: Deliberate Problem Solving with Large Language Models https://github.com/princeton-nlp/tree-of-thought-llm 標題翻譯&#xff1a;思維樹&#xff1a;利用大型語言模型問題求解 1. 內容介紹 1.1. 背景 決策過程有兩種模式&#xff1a; 快速、自動…

使用 Mathematical_Expression 從零開始實現數學題目的作答小游戲【可復制代碼】

從零開始實現數學題目的作答小游戲 開源技術欄 使用 Mathematical_Expression 讓計算機做出題人&#xff0c;讓代碼與數學碰撞出趣味火花。 目錄 文章目錄 從零開始實現數學題目的作答小游戲目錄 從零開始實現數學題目的作答小游戲&#xff1a;讓代碼與數學碰撞出趣味火花為…

DQL-9-小結

DQL-9-小結 小結DQL語句 小結 DQL語句 SELECT 字段列表 -- 字段名 [AS] 別名FROM 表名列表WHERE條件列表 -- >、 >、 <、 <、 、 <>、 like、 between ... and、 in、 and、 or, 分組之前過濾 GROUP BY分組字段列表HAVING分組后條件列表 -- 分組之后…

[netty5: WebSocketServerHandshaker WebSocketServerHandshakerFactory]-源碼分析

在閱讀這篇文章前&#xff0c;推薦先閱讀以下內容&#xff1a; [netty5: WebSocketFrame]-源碼分析[netty5: WebSocketFrameEncoder & WebSocketFrameDecoder]-源碼解析 WebSocketServerHandshakerFactory WebSocketServerHandshakerFactory 用于根據客戶端請求中的 Web…

數據挖掘:深度解析與實戰應用

在當今數字化時代&#xff0c;數據挖掘已經成為企業獲取競爭優勢的關鍵技術之一。通過從大量數據中提取有價值的信息&#xff0c;企業可以更好地理解客戶需求、優化業務流程、提高運營效率。本文將深入探討數據挖掘的核心技術、實際應用案例以及如何在企業中實施數據挖掘項目。…