第一篇:asio网络通讯

开通博客很久了,一直没有写什么有价值的东西,此中缘由一半是因为没什么值得写的,一半是觉得自己所知太少。最近闲下来,想把自己的一些心得体会分享出来,也为自己做一个总结。ok废话不多说了。

最近公司做了一个捕鱼项目,和捕鱼达人玩法相类似的一款手游。

本人是客户端,使用了技术是cocos2dx,版本是3.2的引擎,Java服务器的东西这里就不做赘述(其实是我不了解)。在以后的每期更新中,重点记载一下客户端的相关内同。

因为是网络游戏,第一个重点是网络,第二个重点是游戏。各位即使大拿们如果发现其中的错误,请勿喷。嘴下留情,谢谢

网络:

  关于网络,个人还是比较喜欢原生态的socket通信的,原生态的socket,套用linux的epool封装成异步网络模型,个人还是比较热衷,奈何ios系统不能支持epool(ios支持pool),同时项目负责人对asio比较熟悉,好吧,放弃epool自己封装。ps:后面会补上关于epool封装的心得。

  asio c++ library

  google搜索asio上面第一句就是:

  Asio is a cross-platform C++ library for network and low-level I/O programming that provides developers with a consistent asynchronous model using a modern C++ approach.

  翻译:asio是一个跨平台的提供网络底层,为开发者提供的一个异步模型的网络库。在写此文章的时候asio更新到1.10.4.请下载asio的源码,然后把include中asio文件夹拷贝到项目中,此部分是asio的核心。提供asio的底层支持.同时拷贝asio.hpp文件到项目中,参考源码库中的,该文件与asio文件夹同级,使用的时候直接在需要的文件中添加引用即可 #include <asio.hpp>

  这里添加一点hpp文件说明

  其实质就是将.cpp的实现代码混入.h头文件当中,定义与实现都包含在同一文件,则该类的调用者只需要include该hpp文件即可,无需再将cpp加入到project中进行编译。而实现代码将直接编译到调用者的obj文件中,不再生成单独的obj,采用hpp将大幅度减少调用project中的cpp文件数与编译次数,也不用再发布烦人的lib与dll,因此非常适合用来编写公用的开源库

  hpp的相关内容不再介绍。asio的相关东东,本人仅限于了了解,如果有大神精通,希望大神能给予指点。

  贴第一份代码

//
// AsioSocketClient.cpp

#include <cstdlib>
#include <deque>
#include <iostream>
#include <thread>
#include <asio.hpp>
#include <google/protobuf/message.h>
#include "ReceiveMessage.hpp"
#include "AsioSendMessage.hpp"
#include "CommonMsgHandler.h"
#include "CmdTypeMap.h"
#include "commond/RequestProt.pb.h"

using asio::ip::tcp;
typedef std::deque<AsioSendMessage> SendMessageQueue;


class AsioSocketClient
{
public:
  
  AsioSocketClient(asio::io_service& io_service,
      tcp::resolver::iterator _endpoint_iterator)
    : io_service_(io_service),
      socket_(io_service),
      read_cmdId_(0)
  {
      endpoint_iterator = _endpoint_iterator;
      do_connect(endpoint_iterator, nullptr, nullptr);
  }

  void write(const AsioSendMessage& msg)
  {   
    io_service_.post(
        [this, msg]()
        {   
          bool write_in_progress = !write_msgs_.empty();
          write_msgs_.push_back(msg);
          if (!write_in_progress)
          {
              do_write();
          }
        });
  }

  void close()
  {
    io_service_.post([this]() {
        
        write_msgs_.clear();
        socket_.close();    
    });
  }
    
    
    bool isOpen(){
        return socket_.is_open();
    }

private:
  void do_connect(tcp::resolver::iterator endpoint_iterator , std::function< void(int res) > func_sucess , std::function< void(error_code ec) > func_fail)
  { 
    asio::async_connect(socket_, endpoint_iterator,
        [this, func_sucess, func_fail](std::error_code ec, tcp::resolver::iterator)
        {
          if (!ec)
          { 
            cocos2d::log("Connect success");
            if(func_sucess != nullptr){
                  func_sucess(0);
              }
             do_read_header();  
          }else{  
              if (func_fail != nullptr){
                  func_fail(ec);
              }  
          }
        }); 
  }

  void do_read_header()
  {
    asio::async_read(socket_,
                     asio::buffer(read_msg_.data(), ReceiveMessage::header_length + ReceiveMessage::cmdid_length),
        [this](std::error_code ec, std::size_t /*length*/)
        {
          if (!ec && read_msg_.decode_header(&read_cmdId_))
          {
            do_read_body();
          }
          else
          {   
              EventObject eventObject;
              eventObject.cmd_id = (int)SOCKET_CMD_ERROR;
              eventObject.protobuf_msg = nullptr;
              CommonMsgHandler::sharedMsgHandler()->addEvent(eventObject);
              socket_.close();
          }
        });
  }

  void do_read_body()
  {
    asio::async_read(socket_,
        asio::buffer(read_msg_.body(), read_msg_.body_length()),
        [this](std::error_code ec, std::size_t /*length*/)
        {
          if (!ec)
          {
            void* body_ = malloc(read_msg_.body_length());
            memcpy(body_, read_msg_.body(), read_msg_.body_length());
            chooseCmdId ( read_cmdId_ , body_ ,read_msg_.body_length() );   
            free (body_);
            do_read_header();
          }
          else
          {
              EventObject eventObject;
              eventObject.cmd_id = (int)SOCKET_CMD_ERROR;
              eventObject.protobuf_msg = nullptr;
              CommonMsgHandler::sharedMsgHandler()->addEvent(eventObject);
          }
        });
  }

  void do_write()
  {
      std::error_code ec;
      asio::write(socket_,
                  asio::buffer(write_msgs_.front().data(),
                                        write_msgs_.front().length()),
                  ec);
    if (!ec) {
          if(write_msgs_.front().func_sucess != nullptr){
              write_msgs_.front().func_sucess(0);
          }
          write_msgs_.pop_front();
          if (!write_msgs_.empty())
          {  
              do_write();
          }
      }else{
          if (!write_msgs_.empty())
              write_msgs_.clear();
      }
  }
    
    void chooseCmdId(int32_t cmdid ,void * body ,int size){
        std::string type_name("");
        if (CmdTypeMap::getInstance()->getCmdTypeMap()->find(cmdid) != CmdTypeMap::getInstance()->getCmdTypeMap()->end() ){
            type_name = CmdTypeMap::getInstance()->getCmdTypeMap()->find(cmdid)->second;
        }
        google::protobuf::Message *msg = createMessage(type_name);
        if (!msg) {
            return;
        }
        msg->ParseFromArray(body, size);
        EventObject eventObject;
        eventObject.cmd_id = cmdid;
        eventObject.protobuf_msg = msg;
        CommonMsgHandler::sharedMsgHandler()->addEvent(eventObject);
    }
    
    inline google::protobuf::Message* createMessage(const std::string& type_name)
    {
        google::protobuf::Message* message = NULL;
        const google::protobuf::Descriptor* descriptor =
        google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(type_name);
        if (descriptor)
        {
            const google::protobuf::Message* prototype =
            google::protobuf::MessageFactory::generated_factory()->GetPrototype(descriptor);
            if (prototype)
            {
                message = prototype->New();
            }
        }
        return message;
    }
public:
    void reconnect(string ip, string port, std::function< void(int res) > success_func, std::function< void(error_code ec) > fail_func){
        
        
        using asio::ip::tcp;
        tcp::resolver::query query(ip, port);
        
        tcp::resolver resolver(io_service_);
        auto endpoint_iterator = resolver.resolve(query);
        do_connect(endpoint_iterator, success_func, fail_func);
    }
private:
  asio::io_service& io_service_;
  tcp::resolver::iterator endpoint_iterator;
  tcp::socket socket_;
  ReceiveMessage read_msg_;
  int32_t read_cmdId_;
  SendMessageQueue write_msgs_;
    
};

各位看官会发现,除了上面的几个头文件是系统的,其余要么是google的protobuf,要么是自己写的文件,这些在后面都会一一补上,今天先到这里

2014-11-12

 

posted on 2014-11-12 17:40  水水水水  阅读(433)  评论(0)    收藏  举报

导航