【cocos2dx网络游戏】搭建CS架构的基本通信框架(二)Sever(构建消息体)

来源:互联网 发布:12月份php好找工作吗 编辑:程序博客网 时间:2024/06/05 09:55

虽然C/C++提供了内置的整数类型定义,但不同的计算机硬件体系下整数的宽度是不一样的

32位--》int 4字节

64 int 8字节 

为了使我们以后开发的程序具有跨平台的兼容性,所以我们使用Boost提供的精确宽度的整数定义

为了与客户端统一我们还是把文件建在share目录

新建msg_def.h

#ifndef _MSGDEF_H#define _MSGDEF_H#include <boost/cstdint.hpp>#include <iostream>#include <string>using namespace std;//虽然C/C++提供了内置的整数类型定义,但不同的计算机硬件体系下整数的宽度是不一样的//32位--》int 4字节//64      int 8字节//为了使我们以后开发的程序具有跨平台的兼容性,所以我们使用Boost提供的精确宽度的整数定义//精确宽度整数的定义//使用using引入自己的名字空间using boost::int8_t;using boost::uint8_t;using boost::int16_t;using boost::uint16_t;using boost::int32_t;using boost::uint32_t;using boost::int64_t;using boost::uint64_t;typedef boost::uint8_t byte_t;typedef boost::uint8_t uchar_t;typedef unsigned short ushort_t;typedef unsigned int   uint_t;typedef unsigned long  ulong_t;typedef boost::uint16_t word_t;typedef boost::uint32_t dword_t;//定义消息头的结构struct msg_head{uint32_t type;   //消息类型    整数uint32_t size;   //消息体大小  整数uint32_t chksum; //CRC校验     整数};//如果消息的长度大于 MAX_MSG_SIZE//可以分解数据#define MAX_MSG_SIZE 1024  //消息体最大长度#endif

下面新建消息体tcp_message.h  

使用typedef是因为这命名实在是太长了所以取了一个别名

#ifndef _TCP_MESSAGE_H#define _TCP_MESSAGE_H#include "msg_def.h"#include <boost/checked_delete.hpp>  //待检查的指针删除#include <boost/shared_ptr.hpp>      //智能指针#include <boost/smart_ptr.hpp>#include <boost/array.hpp>           //关于数组的STL容器风格包装#include <boost/function.hpp>#include <boost/noncopyable.hpp>     //禁止拷贝#include <boost/crc.hpp>             //crc校验using namespace boost;//class tcp_session;//typedef boost::shared_ptr<tcp_session> tcp_session_ptr; //共享指针定义//为了避免消息在传递过程中反复拷贝的代价//把该类设计成一个不可拷贝的,这样就强制只能以指针的方式使用;class tcp_message: boost::noncopyable{public://为了支持创建方式的灵活处理,typedef boost::function<void(tcp_message *)> destroy_type;         //销毁器typedef char char_type;typedef boost::array<char_type, sizeof(msg_head)> head_data_type;  //存放消息头的数据(固定大小)typedef boost::array<char_type, MAX_MSG_SIZE> body_data_type;      //存放消息体的数据(不是固定大小)public://template<typename Func>//tcp_message(const tcp_session_ptr &s, Func func);//tcp_message(const tcp_session_ptr &s);//tcp_message();//tcp_session_ptr get_session();tcp_message();template<typename Func>tcp_message(Func func);void destroy();//可以直接访问数据的成员函数head_data_type& head_data();body_data_type& msg_data();//转换为消息头结构的操作msg_head* get_head();//简单的检查消息头是否正确bool check_head();//检查消息体的CRC校验bool check_msg_crc();void set_msg_crc();private://tcp_session_ptr m_session;destroy_type    m_destroy;head_data_type m_head;  //消息头body_data_type m_msg;   //消息体};//这些是一些意义更明确,更便于使用的名称typedef tcp_message   tcp_request;       //tcp请求消息typedef tcp_message   tcp_response;      //tcp响应消息 typedef tcp_request*  tcp_request_ptr;   //tcp请求消息的指针typedef tcp_response* tcp_response_ptr;  //tcp响应消息的指针#endif

tcp_message.cpp

#include "tcp_message.h"// // template<typename Func>// tcp_message::tcp_message(const tcp_session_ptr &s, Func func):// m_session(s), m_destroy(func)// {// // }// // // tcp_message::tcp_message(const tcp_session_ptr &s):// m_session(s)// {// // }// // // tcp_session_ptr tcp_message::get_session()// {// return m_session;// }tcp_message::tcp_message(){}template<typename Func>tcp_message::tcp_message(Func func):m_destroy(func){}//销毁消息void tcp_message::destroy(){//如果传入的销毁器,就使用传入的销毁器进行销毁消息if (m_destroy){m_destroy(this);}else{//使用boost中的销毁器销毁自身boost::checked_delete(this);}}//获取消息头数据tcp_message::head_data_type &tcp_message::head_data(){return m_head;}//获取消息体数据tcp_message::body_data_type &tcp_message::msg_data(){return m_msg;}//将消息头的数据转换为消息体的结构msg_head* tcp_message::get_head(){return reinterpret_cast<msg_head *>(m_head.data());}//简单地检查消息头是否正确bool tcp_message::check_head(){return (get_head()->size < MAX_MSG_SIZE);}//检查消息体的crc校验bool tcp_message::check_msg_crc(){//使用boost的crc库进行简单的校验boost::crc_32_type crc32;//计算校验和crc32.process_bytes(&m_msg[0], get_head()->size);//比较crc值return get_head()->chksum == crc32.checksum();}//在消息头里设置消息体的crc校验void tcp_message::set_msg_crc(){boost::crc_32_type crc32;//计算校验和crc32.process_bytes(&m_msg[0], get_head()->size);//设置校验get_head()->chksum = crc32.checksum();}

上面消息体一已经建好了

我们测试下消息体新建test_tcp_message.h

#ifndef _TEST_TCPMESSAGE_H#define _TEST_TCPMESSAGE_H#include "comm.h"#include "tcp_message.h"void print_msg(boost::shared_ptr<tcp_message> pMsg){cout<<"head type:"<<pMsg->get_head()->type<<endl;cout<<"head size:"<<pMsg->get_head()->size<<endl;cout<<"head checksum:"<<pMsg->get_head()->chksum<<endl;cout<<"data:"<<pMsg->msg_data().data()<<endl;}//test tcp_messagevoid send_data(socket_type sock, const std::string& str){//消息头msg_head head;head.size   = str.length() + 1;head.chksum = std::for_each(str.begin(), str.end(), crc_32_type())();head.type   = 99;//构建消息体boost::shared_ptr<tcp_message> pSendMsg = boost::make_shared<tcp_message>(); pSendMsg->get_head()->chksum = head.chksum;pSendMsg->get_head()->size   = head.size;pSendMsg->get_head()->type   = head.type;//拷贝数据//std::copy(str.begin(), str.end(), pSendMsg->msg_data().begin());memcpy(pSendMsg->msg_data().begin(), str.c_str(), head.size);//设置校验和pSendMsg->set_msg_crc();//阻塞发送//先发送消息头sock->write_some(buffer(pSendMsg->head_data().data(), pSendMsg->head_data().size()));//再发送消息体sock->write_some(buffer(pSendMsg->msg_data().data(), pSendMsg->get_head()->size));int n = pSendMsg->get_head()->size;//输出print_msg(pSendMsg);}std::string  read_data(socket_type sock){//创建消息体boost::shared_ptr<tcp_message> pRecvMsg = boost::make_shared<tcp_message>(); //读消息头sock->read_some(buffer(pRecvMsg->head_data().data(), pRecvMsg->head_data().size()));//读消息体sock->read_some(buffer(pRecvMsg->msg_data().data(), pRecvMsg->get_head()->size));//校验bool bRight = pRecvMsg->check_msg_crc();//输出数据if (bRight){print_msg(pRecvMsg);}return pRecvMsg->msg_data().data();}#endif

上面主要是写了读取和发送消息体,发送的是传人了一个string就是我们要发送的消息

修改下我们昨天用到的main.cpp

#include <iostream>using namespace std;#include "test_tcp_message.h"void proc_data(socket_type sock){//输出客户端的地址的字符串cout<<"client connected :"<<sock->remote_endpoint().address()<<endl;while (true){//捕获可能发生的异常try{cout<<"///////////////////////////////////////////"<<endl;cout<<"recv data from client:"<<endl;std::string strData = read_data(sock);cout<<endl;cout<<"send data to client:"<<endl;send_data(sock, strData);cout<<"///////////////////////////////////////////"<<endl<<endl;}catch(std::exception& e){cout<<e.what()<<endl;break;}}}//处理网络连接void proc_accept(){cout<<"wait connect..."<<endl;io_service ios;  //asio程序必须的io_service对象ip::tcp::endpoint ep(ip::tcp::v4(), PORT_NUM);//用于接收连接ip::tcp::acceptor acceptor(ios, ep);while (true){//初始化一个socket对象socket_type sock(new ip::tcp::socket(ios));//阻塞等待socket连接acceptor.accept(*sock);//为每一个建立连接的客户端建立一个线程处理数据thread t(proc_data, sock);}}int main(int argc, char *argv){//创建线程,以及传递线程处理函数thread t1(proc_accept);//线程阻塞等待,知道线程处理结束t1.join();return 0;};

主要是修改了proc_data函数,先读取了客户端的消息体然后又发送到客户端





0 0
原创粉丝点击