C++ 建立本地网络服务器 (Boost.Asio库)

引言

寸光阴,当下我们或许更需要利用现有的知识,应用现有的技术。网络是当前互联网的根本,了解网络便开始显得极其重要。今天我们利用Boost库中Asio部分,浅尝网络服务器。此处不做过于深入的开展,为达成学习目的,只做简单的异步并发服务器。

 

注意:本篇代码没有直接引用boost等命名空间,为的是新入门Boost的同学能够更好的了解每个参数在boost的具体命名空间位置,有助于更好的理解boost的布局。

 

版权所有:_OE_,转载请注明出处:http://blog.csdn.net/csnd_ayo

码云源代码下载:https://git.oschina.net/Mr_ChenLuYong

CSDN代码下载:http://download.csdn.net/detail/csnd_ayo/9787966

服务器用例

我们在做服务器之前,首先细想一下,服务器应具备哪些基本特质。

1、构建:一个服务器应该具备被连接的IP地址(网络地址)、可以被访问的Port(端口号)

2、聆听:服务器应该能够实时处理基本的连接请求

3、处理:交互才是目的,可以与客户端实现基本的交互

4、异步:处理客户端的请求时,不会因为客户端的延迟响应而导致程序假死

 

建造(Build)

电脑里有非常多的端口,而客户端只会把消息传到约定的地址与端口,只有在正确的端口等待,才能接到自己预期的客户。

就好像楼房里有非常多层楼一样,而快递员只会把物品送到约定的楼层,只有在正确的楼层等待,才能达成预期的结果。

 

 
  1. #include <iostream>

  2. #include <boost/asio.hpp>

  3.  
  4. int main(void) {

  5. try {

  6. std::cout << "server start." << std::endl;

  7. // asio程序必须的io_service对象

  8. boost::asio::io_service ios;

  9. // 具体的服务器地址与端口

  10. boost::asio::ip::tcp::endpoint endpotion(boost::asio::ip::tcp::v4(), 13695);

  11. // 创建acceptor对象,当前的IPV4作为服务器地址(127.0.0.1 || 0.0.0.0),接受端口13695的消息.

  12. boost::asio::ip::tcp::acceptor acceptor(ios, endpotion);

  13. // 打印当前服务器地址

  14. std::cout << "addr: " << acceptor.local_endpoint().address() << std::endl;

  15. // 打印当前服务器端口

  16. std::cout << "port: " << acceptor.local_endpoint().port() << std::endl;

  17. }

  18. catch (...) {

  19. std::cout << "server exceptional." << std::endl;

  20. }

  21. std::cout << "server end." << std::endl;

  22. getchar();

  23. return 0;

  24. }


 

 

聆听(Listen)

一个基本的连接,在正常的情况下,应该由客户端发起,服务器应该处于实时监听的状态,因为能接到客户端发起的连接请求,这才是网络操作的根本。

 

 
  1. #include <iostream>

  2. #include <boost/asio.hpp>

  3.  
  4. int main(void) {

  5. try {

  6. std::cout << "server start." << std::endl;

  7. // asio程序必须的io_service对象

  8. boost::asio::io_service ios;

  9. // 具体的服务器地址与端口

  10. boost::asio::ip::tcp::endpoint endpotion(boost::asio::ip::tcp::v4(), 13695);

  11. // 创建acceptor对象,当前的IPV4作为服务器地址(127.0.0.1 || 0.0.0.0),接受端口13695的消息.

  12. boost::asio::ip::tcp::acceptor acceptor(ios, endpotion);

  13. // 打印当前服务器地址

  14. std::cout << "addr: " << acceptor.local_endpoint().address() << std::endl;

  15. // 打印当前服务器端口

  16. std::cout << "port: " << acceptor.local_endpoint().port() << std::endl;

  17.  
  18. // 循环执行服务

  19. while (true) {

  20. // 一个临时的socket对象

  21. boost::asio::ip::tcp::socket socket(ios);

  22. // 阻塞等待客户端连接,连接成功后返回socket, accept这个函数使用引用来调取socket.

  23. acceptor.accept(socket);

  24. // 打印与本机服务器取得连接的客户端IP地址

  25. std::cout << "client: " << socket.remote_endpoint().address() << std::endl;

  26. }

  27. }

  28. catch (std::exception& _e) {

  29. std::cout << "server exceptional." << std::endl;

  30. std::cout << _e.what() << std::endl;

  31. }

  32. std::cout << "server end." << std::endl;

  33. getchar();

  34. return 0;

  35. }

 

处理(Operation)

一旦服务器收到客户端发起的连接请求,便为客户端建立服务。与客户端建立连接的目的,始终是为了交互,我们不能本末倒置。

我们尝试一下,第一次交互的滋味。

 

 
  1. #include <iostream>

  2. #include <boost/asio.hpp>

  3.  
  4. int main(void) {

  5. try {

  6. std::cout << "server start." << std::endl;

  7. // asio程序必须的io_service对象

  8. boost::asio::io_service ios;

  9. // 具体的服务器地址与端口

  10. boost::asio::ip::tcp::endpoint endpotion(boost::asio::ip::tcp::v4(), 13695);

  11. // 创建acceptor对象,当前的IPV4作为服务器地址(127.0.0.1 || 0.0.0.0),接受端口13695的消息.

  12. boost::asio::ip::tcp::acceptor acceptor(ios, endpotion);

  13. // 打印当前服务器地址

  14. std::cout << "addr: " << acceptor.local_endpoint().address() << std::endl;

  15. // 打印当前服务器端口

  16. std::cout << "port: " << acceptor.local_endpoint().port() << std::endl;

  17.  
  18. // 循环执行服务

  19. while (true) {

  20. // 一个临时的socket对象

  21. boost::asio::ip::tcp::socket socket(ios);

  22. // 阻塞等待客户端连接,连接成功后返回socket, accept这个函数使用引用来调取socket.

  23. acceptor.accept(socket);

  24. // 打印与本机服务器取得连接的客户端IP地址

  25. std::cout << "client: " << socket.remote_endpoint().address() << std::endl;

  26.  
  27.  
  28. //处理/

  29. std::string msg;

  30. // 阻塞发送作者名称到客户端

  31. socket.write_some(boost::asio::buffer("hello CSND_Ayo"));

  32. // 阻塞接收客户端发来的数据

  33. socket.read_some(boost::asio::buffer(msg));

  34. // 打印客户端发来的数据

  35. std::cout << "client reply: " << msg.c_str() << std::endl;

  36. }

  37. }

  38. catch (std::exception& _e) {

  39. std::cout << "server exceptional." << std::endl;

  40. std::cout << _e.what() << std::endl;

  41. }

  42. std::cout << "server end." << std::endl;

  43. getchar();

  44. return 0;

  45. }


 

异步(Async)

处理客户端的请求时,不会因为客户端的延迟响应而导致程序假死

 

 
  1. #include <iostream>

  2. #include <boost/asio.hpp>

  3. #include <boost/bind.hpp>

  4.  
  5. // 异步服务器类

  6. class Server {

  7.  
  8. private:

  9.  
  10. // 服务实例

  11. boost::asio::io_service& ios_;

  12.  
  13. // 接收器实例

  14. boost::asio::ip::tcp::acceptor acceptor_;

  15.  
  16. // socket智能指针

  17. typedef boost::shared_ptr<boost::asio::ip::tcp::socket> socket_ptr;

  18.  
  19. public:

  20.  
  21. Server(boost::asio::io_service& _ios) : ios_(_ios),

  22. acceptor_(_ios, boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), 13695)) {

  23. // 默认执行

  24. start();

  25. }

  26.  
  27. // 启动网络侦听的操作入口

  28. void start(void) {

  29. // 自定义的智能指针

  30. socket_ptr socket(new boost::asio::ip::tcp::socket(ios_));

  31. // 异步侦听,若有服务连接,则自动调用Server::handler_accept函数,并将error, socket传入作为参数

  32. acceptor_.async_accept(*socket,

  33. boost::bind(&Server::accept_handler, this,

  34. boost::asio::placeholders::error/* 此处作为占位符 */, socket));

  35. }

  36.  
  37. // 请求者响应后触发的处理器

  38. void accept_handler(const boost::system::error_code& _ec, socket_ptr _socket) {

  39. // 错误码检测

  40. if (_ec) {

  41. return;

  42. }

  43. // 打印当前连接进来的客户端

  44. std::cout << "client: " << _socket->remote_endpoint().address() << std::endl;

  45. // 异步发送 "hello CSND_Ayo" 消息到客户端,发送成功后,自动调用Server::write_handler函数

  46. _socket->async_write_some(boost::asio::buffer("hello CSND_Ayo"),

  47. boost::bind(&Server::write_handler, this,

  48. boost::asio::placeholders::error/* 此处作为占位符 */));

  49. // 启动新的异步监听

  50. start();

  51. }

  52.  
  53. // 完成异步写操作后的处理器

  54. void write_handler(const boost::system::error_code& _ec) {

  55. std::cout << "server: send message complete." << std::endl;

  56. }

  57.  
  58. };

  59.  
  60.  
  61.  
  62. int main(void) {

  63. try {

  64. std::cout << "server start." << std::endl;

  65. // 建造服务对象

  66. boost::asio::io_service ios;

  67. // 构建Server实例

  68. Server server(ios);

  69. // 启动异步调用事件处理循环

  70. ios.run();

  71. }

  72. catch (std::exception& _e) {

  73. std::cout << _e.what() << std::endl;

  74. }

  75. std::cout << "server end." << std::endl;

  76. return 0;

  77. }


 

 

作者的简易并发服务器类

使用两个类来撰写了一个并发的服务器类
Server(服务器监听类)、Session(会话类)

 

具备功能:

1、异步监听客户端连接

2、客户连接时,首包要求具有特定格式(协议包)

3、并发处理客户端交互

 

当前类的网络交互协议拓扑图

 

Server.h

 

 
  1. #ifndef __CLY_SERVER_H__

  2. #define __CLY_SERVER_H__

  3. #include <string.h>

  4. #include <boost/asio.hpp>

  5. #include <boost/shared_ptr.hpp>

  6. class Session;

  7. class Server {

  8. private:

  9. // 会话 - 智能指针

  10. typedef boost::shared_ptr<Session> session_ptr;

  11. public:

  12. Server(boost::asio::io_service &_ioService, boost::asio::ip::tcp::endpoint &_endpoint);

  13. virtual ~Server(void);

  14. // 监听

  15. void start(void);

  16. // 异步

  17. void run(void);

  18. private:

  19. // 数据导出接口

  20. void callback_session(std::string _fromIp, std::string _info);

  21. // 会话启动

  22. void accept_handler(session_ptr _chatSession, const boost::system::error_code& _error);

  23. private:

  24. boost::asio::io_service &ioService_;

  25. boost::asio::ip::tcp::acceptor acceptor_;

  26. };

  27. #endif // __CLY_SERVER_H__

 

 

Server.cpp

 

 
  1. #include <boost/bind.hpp>

  2.  
  3. #include "Server.h"

  4. #include "Session.h"

  5.  
  6.  
  7. Server::Server(boost::asio::io_service &_ioService, boost::asio::ip::tcp::endpoint &_endpoint)

  8. : ioService_(_ioService), acceptor_(_ioService, _endpoint) {

  9. start();

  10. }

  11.  
  12.  
  13. Server::~Server(void) {

  14. }

  15.  
  16. void Server::start(void) {

  17. session_ptr new_chat_session(new Session(ioService_));

  18.  
  19. acceptor_.async_accept(new_chat_session->socket(),

  20. boost::bind(&Server::accept_handler, this, new_chat_session,

  21. boost::asio::placeholders::error));

  22. }

  23.  
  24. void Server::run(void) {

  25. ioService_.run();

  26. }

  27.  
  28. void Server::callback_session(std::string /*_fromIp*/, std::string /*_info*/) {

  29. return;

  30. }

  31.  
  32. void Server::accept_handler(session_ptr _chatSession, const boost::system::error_code& _error) {

  33. if (!_error && _chatSession) {

  34. try {

  35. _chatSession->start();

  36. start();

  37. }

  38. catch (...) {

  39. return;

  40. }

  41. }

  42. }


Session.h

 
  1. #ifndef __CLY_SESSION_H__

  2. #define __CLY_SESSION_H__

  3.  
  4. #include <iostream>

  5. #include <string>

  6.  
  7. #include <boost/asio.hpp>

  8. #include <boost/enable_shared_from_this.hpp>

  9.  
  10. #define REPLY_SIZE (32)

  11.  
  12. // 会话类

  13. class Session : public boost::enable_shared_from_this<Session>

  14. {

  15.  
  16. public:

  17.  
  18. typedef void pSessionCallback(std::string, std::string);

  19.  
  20. public:

  21.  
  22. Session(boost::asio::io_service& _ioService);

  23. virtual ~Session(void);

  24.  
  25. void start(void);

  26.  
  27. void setCallback(pSessionCallback* _callback) { callback_ = _callback; }

  28.  
  29. // socket 实例

  30. boost::asio::ip::tcp::socket& socket(void);

  31.  
  32. private:

  33.  
  34. // 第一个协议包

  35. void init_handler(const boost::system::error_code& _error);

  36.  
  37. // 解析协议包

  38. void analyse_handler(const boost::system::error_code& _error);

  39.  
  40. // 完成数据传输后触发的收尾工作

  41. void done_handler(const boost::system::error_code& _error);

  42.  
  43. // 读取成功后触发的函数

  44. void read_handler(const boost::system::error_code& _error, size_t _readSize);

  45.  
  46. // 写入完成后触发的函数

  47. void write_handler(const boost::system::error_code& _error);

  48.  
  49. private:

  50. // 临时信息缓冲区

  51. char msg_[1024];

  52. std::string currentMsg_;

  53. // 数据总数量

  54. int sumSize_;

  55. // 单个数据包大小

  56. unsigned int maxSize_;

  57. // socket句柄

  58. boost::asio::ip::tcp::socket socket_;

  59. // 回调

  60. pSessionCallback* callback_;

  61.  
  62. };

  63.  
  64.  
  65. #endif // __CLY_SESSION_H__


Session.cpp

 

 

 
  1. #include <boost/bind.hpp>

  2.  
  3. #include "Session.h"

  4.  
  5.  
  6. Session::Session(boost::asio::io_service& _ioService)

  7. :socket_(_ioService) {

  8. memset(msg_, 0, sizeof(msg_));

  9. }

  10.  
  11.  
  12. Session::~Session(void)

  13. {

  14. }

  15.  
  16.  
  17. void Session::start(void) {

  18. // 告诉链接成功的客户端,你想要的信息。

  19. char msg[256] = "001:Connect Succeed! Please tell me with 10 bytes, the total data and the size of each package, example:128 1024";

  20. boost::asio::async_write(socket_, boost::asio::buffer(msg, strlen(msg)),

  21. boost::bind(&Session::init_handler, shared_from_this(),

  22. boost::asio::placeholders::error));

  23. }

  24.  
  25. boost::asio::ip::tcp::socket& Session::socket(void) {

  26. return socket_;

  27. }

  28.  
  29.  
  30. // 第一个协议包

  31. void Session::init_handler(const boost::system::error_code& _error) {

  32. if (_error) {

  33. return;

  34. }

  35. // 读取客户端发来的 10 bytes,确定单个包的大小以及数据总大小

  36. boost::asio::async_read(socket_, boost::asio::buffer(msg_, 10),

  37. boost::bind(&Session::analyse_handler, shared_from_this(),

  38. boost::asio::placeholders::error));

  39.  
  40. }

  41.  
  42. void Session::analyse_handler(const boost::system::error_code& _error) {

  43. if (_error) {

  44. return;

  45. }

  46. // 分析协议包格式

  47. bool bflag = true;

  48. // 正则分析格式

  49.  
  50. // do something.

  51. if (!bflag) {

  52. start();

  53. return;

  54. }

  55.  
  56. // 格式化保存协议包数据

  57. std::stringstream io(msg_);

  58. io >> maxSize_;

  59. io >> sumSize_;

  60.  
  61. // 发送接收请求信息

  62. char msg[REPLY_SIZE];

  63. sprintf_s(msg, "001:is ok, data remaining %d.", sumSize_);

  64. boost::asio::async_write(socket_, boost::asio::buffer(msg, REPLY_SIZE),

  65. boost::bind(&Session::write_handler, shared_from_this(),

  66. boost::asio::placeholders::error));

  67. }

  68.  
  69.  
  70. // 完成数据传输

  71. void Session::done_handler(const boost::system::error_code& _error) {

  72. if (_error) {

  73. return;

  74. }

  75. currentMsg_ += msg_;

  76. // 发送信息到回调

  77. if (!currentMsg_.empty() && callback_ != nullptr) {

  78. callback_(socket_.remote_endpoint().address().to_string(), currentMsg_);

  79. currentMsg_.clear();

  80. }

  81. memset(msg_, 0, sizeof(msg_));

  82.  
  83. char msg[32] = "001:will done.";

  84. boost::asio::async_write(socket_, boost::asio::buffer(msg, REPLY_SIZE),

  85. boost::bind(&Session::init_handler, shared_from_this(),

  86. boost::asio::placeholders::error));

  87. }

  88.  
  89. void Session::read_handler(const boost::system::error_code& _error, size_t _readSize) {

  90. if (_error) {

  91. return;

  92. }

  93. // 数据处理

  94. currentMsg_ += msg_;

  95. if (currentMsg_.size() > 1024 * 512) {

  96. // 发送信息到回调

  97. if (callback_ != nullptr) {

  98. callback_(socket_.remote_endpoint().address().to_string(), currentMsg_);

  99. currentMsg_.clear();

  100. }

  101. }

  102. memset(msg_, 0, sizeof(msg_));

  103.  
  104. // 计算当前剩余数据数量

  105. sumSize_ -= _readSize;

  106.  
  107. // 接收完成

  108. if (0 > sumSize_) {

  109. done_handler(_error);

  110. }

  111. // 继续接收

  112. else {

  113. char msg[REPLY_SIZE];

  114. sprintf_s(msg, "001:%d.", sumSize_);

  115. boost::asio::async_write(socket_, boost::asio::buffer(msg, REPLY_SIZE),

  116. boost::bind(&Session::write_handler, shared_from_this(),

  117. boost::asio::placeholders::error));

  118.  
  119. std::cout << "send client recv succeed: " << msg << std::endl;

  120. }

  121.  
  122.  
  123.  
  124. }

  125. void Session::write_handler(const boost::system::error_code& _error) {

  126. if (_error) {

  127. return;

  128. }

  129.  
  130. boost::asio::async_read(socket_, boost::asio::buffer(msg_, maxSize_),

  131. boost::bind(&Session::read_handler, shared_from_this(),

  132. boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));

  133. }


 

 

main.cpp

 

 
  1. #include <iostream>

  2. #include <boost/asio.hpp>

  3. #include <boost/bind.hpp>

  4.  
  5. #include "Server.h"

  6.  
  7. int main(void) {

  8. try {

  9. std::cout << "server start." << std::endl;

  10. // 建造服务对象

  11. boost::asio::io_service ios;

  12. // 具体的服务器地址与端口

  13. boost::asio::ip::tcp::endpoint endpotion(boost::asio::ip::tcp::v4(), 13695);

  14. // 构建Server实例

  15. Server server(ios, endpotion);

  16. // 启动异步调用事件处理循环

  17. server.run();

  18. }

  19. catch (std::exception& _e) {

  20. std::cout << _e.what() << std::endl;

  21. }

  22. std::cout << "server end." << std::endl;

  23. return 0;

  24. }

 

原文:https://blog.csdn.net/csnd_ayo/article/details/61577634

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值