news 2025/12/17 3:02:06

asio的socket创建与连接的基础实现和与C风格的socket网络通信的对比

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
asio的socket创建与连接的基础实现和与C风格的socket网络通信的对比

asio socket创建与连接的基础实现和与C风格的socket网络通信的对比

一、整体功能概述

基于Boost.Asio库实现了 TCP 网络编程的核心基础操作,涵盖了端点(endpoint)创建TCP 套接字(socket)创建服务端监听器(acceptor)创建与绑定客户端连接(直连 IP / 域名解析)服务端接受连接等关键步骤。

Boost.Asio 是 C++ 的异步 I/O 库,封装了操作系统的网络 API,提供了更优雅的面向对象接口和跨平台能力。


二、代码模块解析

1. 头文件与命名空间
#include<boost/asio.hpp>// Boost.Asio核心头文件#include<iostream>usingnamespaceboost;// 简化boost命名空间使用(实际项目中不建议全局using,易冲突)
  • Boost.Asio 的核心组件都在boost::asio命名空间下,比如io_contextip::tcpsocketacceptor等。
2. 端点(Endpoint)创建:client_end_point&server_end_point

端点是网络通信的地址 + 端口抽象,对应 TCP/IP 的套接字地址结构(如 C 语言的sockaddr_in)。

  • C 语言的sockaddr_in
struct sockaddr_in { unsigned short sin_family; // 协议族,与 socket()函数的第一个参数相同。 unsigned short sin_port; // 16 位端口号,大端序。用 htons(整数的端口)转换。 struct in_addr sin_addr; // IP 地址的结构体。192.168.101.138 unsigned char sin_zero[8]; // 未使用,为了保持与 struct sockaddr 一样的长度而添加。 };
  • Boost.Asio创建 TCP 客户端和服务端端点(endpoint
// 客户端端点(指定具体IP和端口)intclient_end_point(){std::string raw_ip_address="127.4.8.1";unsignedshortport_num=3333;boost::system::error_code ec;// Boost的错误码(替代异常,更灵活)// 解析IP地址(字符串→asio::ip::address对象)asio::ip::address ip_address=asio::ip::make_address(raw_ip_address,ec);if(ec.value()!=0){// 错误处理std::cout<<"Failed to parse the IP address Error code = "<<ec.value()<<".Message is "<<ec.message();returnec.value();}// 创建TCP端点(IP+端口)asio::ip::tcp::endpointep(ip_address,port_num);return0;}// 服务端端点(绑定所有IPv6地址+端口,也可改用v4::any())intserver_end_point(){unsignedshortport_num=3333;asio::ip::address ip_address=asio::ip::address_v6::any();// 通配地址:监听所有网卡asio::ip::tcp::endpointep(ip_address,port_num);return0;}
  • 核心逻辑:将字符串 IP 解析为 Asio 的ip::address对象,再结合端口创建ip::tcp::endpoint(封装了地址和端口的面向对象结构)。
  • 错误处理:使用boost::system::error_code替代异常(也可使用异常,Asio 支持两种方式)。
3. TCP 套接字创建:create_tcp_socket

套接字是网络通信的文件描述符抽象,Asio 用ip::tcp::socket类封装。

intcreate_tcp_socket(){asio::io_context ioc;// Asio的核心:I/O上下文(管理所有I/O操作的事件循环)asio::ip::tcp protocol=asio::ip::tcp::v4();// 指定TCPv4协议asio::ip::tcp::socketsock(ioc);// 创建套接字(关联I/O上下文)boost::system::error_code ec;sock.open(protocol,ec);// 打开套接字(对应C语言的socket()函数)if(ec.value()!=0){std::cout<<"Failed to open the socket! Error code = "<<ec.value()<<".Message is "<<ec.message();returnec.value();}return0;}
  • 关键组件io_context是 Asio 的核心,所有 I/O 操作(如读写、连接、接受)都需要关联到它,它负责调度事件。
  • sock.open():对应 C 语言的socket(AF_INET, SOCK_STREAM, 0)(创建 TCP 套接字)。
4. 服务端监听器(Acceptor)创建:create_acceptor_socket&bind_acceptor_socket

服务端需要用acceptor(监听器)绑定端口并监听连接,Asio 的ip::tcp::acceptor封装了这一逻辑。

// 新版便捷写法:一行完成创建、打开、绑定intcreate_acceptor_socket(){asio::io_context ios;asio::ip::tcp::acceptora(ios,asio::ip::tcp::endpoint(asio::ip::tcp::v4(),3333));return0;}// 老版本:分步实现(打开→绑定)intbind_acceptor_socket(){unsignedshortport_num=3333;asio::ip::tcp::endpointep(asio::ip::address_v4::any(),port_num);asio::io_context ios;asio::ip::tcp::acceptoracceptor(ios,ep.protocol());// 打开协议(TCPv4)boost::system::error_code ec;acceptor.bind(ep,ec);// 绑定端点(对应C语言的bind())if(ec.value()!=0){std::cout<<"Failed to bind the acceptor socket."<<"Error code = "<<ec.value()<<".Message: "<<ec.message();returnec.value();}}
  • acceptor的作用:对应 C 语言的socket() + bind() + listen()组合,Asio 提供了便捷构造函数(直接传入 endpoint,一步完成所有操作)和分步操作(更灵活)两种方式。
  • ip::address_v4::any():对应 C 语言的INADDR_ANY(绑定所有网卡的 IP)。
5. 客户端连接:connect_to_end(直连 IP)&dns_connect_to_end(域名解析)

客户端通过套接字连接服务端端点,Asio 封装了连接和 DNS 解析逻辑。

// 直连IP:同步连接intconnect_to_end(){std::string raw_ip_address="192.168.1.124";unsignedshortport_num=3333;try{asio::ip::tcp::endpointep(asio::ip::make_address(raw_ip_address),port_num);asio::io_context ios;asio::ip::tcp::socketsock(ios,ep.protocol());// 创建套接字sock.connect(ep);// 连接端点(对应C语言的connect())}catch(system::system_error&e){// 异常处理(替代error_code)std::cout<<"Error occured! Error code = "<<e.code()<<".Message: "<<e.what();returne.code().value();}}// 域名解析连接:通过DNS获取IP后连接intdns_connect_to_end(){std::string host="llfc.club";std::string port_num="3333";asio::io_context ios;try{asio::ip::tcp::resolverresolver(ios);// DNS解析器// 解析域名→多个端点(可能是IPv4/IPv6)asio::ip::tcp::resolver::results_type endpoints=resolver.resolve(host,port_num);asio::ip::tcp::socketsock(ios);// 遍历端点并连接(Asio自动处理,直到成功或失败)asio::connect(sock,endpoints);}catch(system::system_error&e){std::cout<<"Error occured! Error code = "<<e.code()<<".Message: "<<e.what();returne.code().value();}}
  • resolver(解析器):对应 C 语言的getaddrinfo()(DNS 解析),Asio 封装了解析过程,返回results_type(多个端点的集合)。
  • asio::connect():自动遍历解析后的端点,尝试连接,直到成功或全部失败(简化了 C 语言中手动遍历addrinfo链表的逻辑)。
6. 服务端接受连接:accept_new_connection

服务端通过acceptor接受客户端的连接请求,得到一个新的套接字用于通信。

intaccept_new_connection(){constintBACKLOG_SIZE=30;// 监听队列大小(对应listen()的backlog参数)unsignedshortport_num=3333;asio::ip::tcp::endpointep(asio::ip::address_v4::any(),port_num);asio::io_context ios;try{asio::ip::tcp::acceptoracceptor(ios,ep.protocol());acceptor.bind(ep);// 绑定端口acceptor.listen(BACKLOG_SIZE);// 开始监听(对应C语言的listen())asio::ip::tcp::socketsock(ios);acceptor.accept(sock);// 阻塞等待连接(对应C语言的accept())// 此时sock是与客户端通信的套接字}catch(system::system_error&e){std::cout<<"Error occured! Error code = "<<e.code()<<".Message: "<<e.what();returne.code().value();}}
  • acceptor.listen(BACKLOG_SIZE):设置监听队列大小,对应 C 语言的listen(sockfd, BACKLOG_SIZE)
  • acceptor.accept(sock):阻塞等待客户端连接,成功后将新的套接字写入sock(对应 C 语言的accept()返回新的文件描述符)。

三、与 C 语言 BSD Socket 的对比

C 语言的 BSD Socket 是过程式的底层 API,直接调用操作系统的系统调用;而 Boost.Asio 是面向对象的封装,基于 C++ 的特性(如类、异常、模板)简化了开发,同时保留了底层功能的灵活性。以下是关键操作的对比:

功能步骤Boost.Asio(C++)实现C 语言 BSD Socket 实现
1. 初始化需创建io_context(I/O 上下文,管理所有 I/O 操作)无需初始化,直接调用系统调用
2. 创建 TCP 套接字asio::ip::tcp::socket sock(ioc); sock.open(tcp::v4());int sockfd = socket(AF_INET, SOCK_STREAM, 0);(返回文件描述符
3. 定义端点 / 地址asio::ip::tcp::endpoint ep(ip::make_address("127.0.0.1"), 3333);(面向对象)手动填充sockaddr_in结构体:
struct sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(3333);
inet_pton(AF_INET, "127.0.0.1", &addr.sin_addr);
4. 服务端绑定端口acceptor.bind(ep);(acceptor 封装了套接字)bind(sockfd, (struct sockaddr*)&addr, sizeof(addr));(需强制类型转换)
5. 服务端监听acceptor.listen(BACKLOG_SIZE);listen(sockfd, BACKLOG_SIZE);
6. 服务端接受连接acceptor.accept(sock);(新连接写入 sock 对象)int clientfd = accept(sockfd, (struct sockaddr*)&client_addr, &addr_len);(返回新文件描述符)
7. 客户端连接sock.connect(ep);(直接传入 endpoint 对象)connect(sockfd, (struct sockaddr*)&addr, sizeof(addr));(需强制类型转换)
8. DNS 域名解析resolver.resolve(host, port);+asio::connect(sock, endpoints);(自动遍历端点)调用getaddrinfo()获取addrinfo链表,手动遍历链表并调用connect(),最后释放freeaddrinfo()
9. 错误处理支持两种方式:
1.boost::system::error_code(返回错误码)
2. 异常捕获(system_error
检查函数返回值(如-1),通过errno获取错误码,调用perror()strerror()查看信息
10. 跨平台自动适配 Windows/Linux/macOS(Asio 封装了不同系统的差异)需处理系统差异:
Windows 需初始化 WSA(WSAStartup()
数据类型差异(如SOCKETvsint
函数名差异(如closesocket()vsclose()
11. 异步操作原生支持异步 I/O(如async_connectasync_acceptasync_read/write),通过回调或协程处理需手动实现(如使用 select/poll/epoll/kqueue,或线程),开发复杂度高

四、核心差异总结

  1. 编程范式

    • C 语言过程式,基于文件描述符(整数)和结构体,手动管理内存和资源,代码冗长且易出错(如强制类型转换、结构体填充、内存释放)。
    • Boost.Asio面向对象,用socketacceptorendpoint等类封装底层操作,隐藏了繁琐的细节(如字节序转换、地址结构体填充)。
  2. 错误处理

    • C 语言:通过返回值(如-1)和errno判断错误,需手动调用perror()strerror()解析错误信息。
    • Boost.Asio:支持错误码error_code)和异常两种方式,错误信息更丰富(包含错误码和描述),且类型安全。
  3. DNS 解析

    • C 语言:需手动调用getaddrinfo(),遍历返回的addrinfo链表,处理每个端点的连接,最后释放资源。
    • Boost.Asio:用resolver自动解析域名,返回results_typeasio::connect()自动遍历端点并连接,简化了代码。
  4. 异步 I/O

    • C 语言:异步操作需手动使用select/epoll/kqueue等 I/O 多路复用技术,或线程池,开发难度大。
    • Boost.Asio:原生支持异步操作(async_*系列函数),通过回调函数、协程(C++20)或future处理结果,是 Asio 的核心优势之一。
  5. 跨平台性

    • C 语言:需处理不同系统的差异(如 Windows 的 WSA 初始化、closesocket()vsclose())。
    • Boost.Asio:封装了系统差异,代码无需修改即可在不同平台运行。

五、注意事项

  1. io_context的作用:Asio 的所有 I/O 操作都依赖io_context,即使是同步操作,也需要创建它(异步操作还需要调用io_context.run()启动事件循环)。
  2. 异常与错误码:代码中同时使用了异常和error_code,Asio 的所有操作都提供了两种重载(带error_code参数的版本不抛异常,不带的版本抛异常),可根据场景选择。
  3. 命名空间:代码中使用using namespace boost;简化代码,但实际项目中建议使用namespace ba = boost::asio;这样的别名,避免命名冲突。
  4. 资源管理:Asio 的类(如socketacceptor)都实现了 RAII(资源获取即初始化),析构时会自动释放资源(如关闭套接字),无需手动调用close()(C 语言需手动关闭文件描述符)。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/17 3:01:53

LobeChat OCR插件开发设想:让AI看懂图片中的文字

LobeChat OCR插件开发设想&#xff1a;让AI看懂图片中的文字 在智能对话系统日益普及的今天&#xff0c;用户早已不满足于“纯文本”的交互方式。试想这样一个场景&#xff1a;你刚收到一份扫描版合同&#xff0c;想快速确认其中的关键条款&#xff1b;或是学生拍下一道复杂的数…

作者头像 李华
网站建设 2025/12/17 2:58:41

LobeChat标杆客户访谈提纲

LobeChat&#xff1a;重塑AI交互的开源实践 在大语言模型能力突飞猛进的今天&#xff0c;一个反直觉的现象正在发生——技术越强大&#xff0c;用户体验反而越割裂。我们手握GPT-4、Claude 3这样的“超级大脑”&#xff0c;却依然被困在API密钥管理、命令行调试和碎片化工具之间…

作者头像 李华
网站建设 2025/12/17 2:58:03

干掉 VMware!!ProxmoxVE 真香~

往期热门文章&#xff1a;1、有哪些话一听就知道一个程序员是个水货&#xff1f; 2、CompletableFuture的5个大坑&#xff01; 3、Spring 项目别再乱注入 Service 了&#xff01;用 Lambda 封装个统一调用组件&#xff0c;爽到飞起 4、再见Maven&#xff01;官方推出全新一代Ja…

作者头像 李华
网站建设 2025/12/17 2:58:03

2、量子场论:现实的基石

量子场论:现实的基石 20 世纪初,确切地说是 20 世纪 30 年代的欧洲,见证了人类历史上最伟大的理论之一——量子力学的诞生。经过近一个世纪的发展,这个充满想象力的奇迹不断演变并衍生出多个方向,其中之一便是量子场论(QFT)。如果你热爱物理学并希望理解事物为何如此,那…

作者头像 李华
网站建设 2025/12/17 2:57:33

12、量子计算中的数学基础:从欧拉恒等式到量子门

量子计算中的数学基础:从欧拉恒等式到量子门 欧拉恒等式:绝妙的杰作 欧拉恒等式是量子计算的基石,由瑞士数学家欧拉提出。其公式为: 这个公式无处不在,不仅在量子力学中,几乎在所有数学领域都有应用,因此必须牢记。它之所以令人惊叹,是因为它将以下元素联系在一起:…

作者头像 李华