简单的聊天室服务器 基于Boost asio(4)--服务器设计

这篇文章主要解析,聊天室服务器的设计。
所用的函数基本都来自于boost库,通过阅读官方的文档,来了解具体的实现操作以及函数的作用。
首先,他是通过一个TCP连接来提供服务。
通过asio的io_service来实现与底层操作系统io之间的对接。
通过,async_()来实现异步的收发消息。
通过一个双向队列deque来实现存储消息的数据结构。
通过tcp::endpoint来监听消息传递
通过 tcp::socket 设置套接桥梁,消息传输管道

using chat_message_queue = std::deque<chat_message>;
**实现一个聊天室功能,所有的人进来后都存在于聊天室中,发出的消息其他处在聊天室中的人都可以看到。
添加客户端加入,退出功能。
实现群发分发消息功能。
并且存储一百条消息记录,使用一个双向链表来实现消息的淘汰和刷新**


class chat_room {
public:
public:
	void join(chat_session_ptr);
	void leave(chat_session_ptr);
	void deliver(const chat_message&);
private:
  std::set<chat_session_ptr> participants_;
  enum { max_recent_msgs = 100 };
  chat_message_queue recent_msgs_;
};
//有人加入后存储客户,分发以前的消息。
 void chat_room::join(chat_session_ptr participant) {
    participants_.insert(participant);
    for (const auto& msg : recent_msgs_)
      participant->deliver(msg);
  }
  //有人离开后 删除客户
  void chat_room::leave(chat_session_ptr participant) {
    participants_.erase(participa3nt);
  }
//新客户进来之后 分发存储的100条消息 让新客户知道聊了点什么
  void chat_room::deliver(const chat_message &msg) {
    recent_msgs_.push_back(msg);
    while (recent_msgs_.size() > max_recent_msgs)
      recent_msgs_.pop_front();
    for (auto& participant : participants_)
      participant->deliver(msg);
  }




/**实现消息的处理功能,一个新消息进来后,服务器将会接收到消息的类型和消息的实在。接收到之后,要分发出去让其他的客户看到。**/


/实现消息的处理功能,一个新消息进来后,服务器将会接收到消息的类型和消息的实在。接收到之后,要分发出去让其他的客户看到。/
/*读写消息
**** boost::asio::async_read表示使用异步的方式,异步相对于同步而言更加的灵活而且更加的健壮,效率更高。
/**
而在读取头部之后如果没有发生错误,就去立马读取消息实体,读完消息实体之后又返回去读取吓一跳消息的头部。如此循环就实现了消息的不断读取。

class chat_session : public std::enable_shared_from_this<chat_session> {
public:
  chat_session(tcp::socket socket, chat_room &room)
      : socket_(std::move(socket)), room_(room) {
//读取消息头部
  void do_read_header() {
    auto self(shared_from_this());
    boost::asio::async_read(
        socket_,
        boost::asio::buffer(read_msg_.data(), chat_message::header_length),
        [this, self](boost::system::error_code ec, std::size_t /*length*/) {
          if (!ec && read_msg_.decode_header()) {
            do_read_body();
        });
  } 
  //读取消息实体
   void do_read_body() {
    auto self(shared_from_this());
    boost::asio::async_read(
        socket_, boost::asio::buffer(read_msg_.body(), read_msg_.body_length()),
        [this, self](boost::system::error_code ec, std::size_t /*length*/) {
          if (!ec) {
            //room_.deliver(read_msg_);
						handleMessage();
            do_read_header();
        });
  }

到此,发现还需要一个方法去分析如何处理这些信息。
如果是客户发过来的消息类型或者消息实体,如何去处理他。
而服务器如何将受到的消息广播给每一个客户收取。也需要去具体化。以下函数就是对于收发消息的选择与控制。

  void handleMessage() {
    if (read_msg_.type() == MT_BIND_NAME) {
   
			auto bindName = toObject<SBindName>();
			m_name = bindName.bindName();
    } else if (read_msg_.type() == MT_CHAT_INFO) {
			auto chat = toObject<SChatInfo>();
			m_chatInformation = chat.chatInformation()
      auto rinfo = buildRoomInfo();
      chat_message msg;
      msg.setMessage(MT_ROOM_INFO, rinfo);
      room_.deliver(msg)

//服务器写入消息,为了广播给所有的客户
void do_write() {
    auto self(shared_from_this());
    boost::asio::async_write(
        socket_, boost::asio::buffer(write_msgs_.front().data(),
                                     write_msgs_.front().length()),
        [this, self](boost::system::error_code ec, std::size_t /*length*/) {
          if (!ec) {
            write_msgs_.pop_front();
            if (!write_msgs_.empty()) 
              do_write();
//服务器接收到消息后处理
  void do_accept() {
    acceptor_.async_accept(socket_, [this](boost::system::error_code ec) {
      if (!ec) {
        auto session =
            std::make_shared<chat_session>(std::move(socket_), room_);
        session->start();
      }
boost::asio::io_service io_service;//使用io_service实现与操作系统之间io操作
tcp::endpoint endpoint(tcp::v4(), std::atoi(argv[i]));//使用enpoint监听
servers.emplace_back(io_service, endpoint);//监听到的消息插入io_service
io_service.run();

emplace_back: 在容器尾部添加一个元素,这个元素原地构造,不需要触发拷贝构造和转移构造。而且调用形式更加简洁,直接根据参数初始化临时对象的成员。 相对于push_back来说更加的省空间。

服务器实现的巧妙而又简单,通过deque来完美展现了缓存消息的处理,又使用了交替的读写结构模拟不断的收发消息。
error提供了简单而又稳定的错误监测结构,避免了在出错时抛出异常,卡死线程,进而崩溃掉。
总的来说,设计简单而又巧妙,值得初学者去解析和阅读。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 适合毕业设计、课程设计作业。这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。 所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问题欢迎随时与博主沟通,第一时间进行解答!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值