【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
- 【cocos2dx网络游戏】搭建CS架构的基本通信框架(二)Sever(构建消息体)
- 【cocos2dx网络游戏】搭建CS架构的基本通信框架(二)Client(构建消息体)
- 【cocos2dx网络游戏】搭建CS架构的基本通信框架(一)server
- 【cocos2dx网络游戏】搭建CS架构的基本通信框架(一)Client
- 基于cocos2dx的网络游戏基本框架
- 基于cocos2dx的网络游戏基本框架
- NIO(二)--CS架构的非阻塞通信
- U3D框架搭建之消息系统(前端通信)
- 网络游戏中通信消息的组织
- 网络游戏的基本编程技术、架构
- [Unity通信]一个基于socket的3DARPG网络游戏(二):消息分类处理和json的使用
- 我的游戏框架基础构建篇(cocos2dx 循环滚动地图的实现)
- SpringCloud构建微服务入门架构(二)服务注册与发现Eureka集群搭建
- Struts2框架的基本使用(二)
- ssh2框架的搭建(二)
- 搭建自己的SQLiteDataBase框架(二)
- SSH框架的搭建(二)
- 网络游戏制作技术(二)
- Spring MVC的多视图解析器配置及与Freemarker的集成
- 如何锁定Excel中的部分单元格
- Lua基础学习开篇——类型和运算符
- 使用Memcached、Spring AOP构建数据库前端缓存框架
- SDUT14级队员训练1 G - DNA Consensus String
- 【cocos2dx网络游戏】搭建CS架构的基本通信框架(二)Sever(构建消息体)
- eclipse Freemarker插件
- 九度OJ;题目1147:Jugs
- 在同声传译这件事上,Skype是如何击败99.9%的地球人的?
- 看了这个才发现jQuery源代码不是那么晦涩
- Lua基础学习二——表和函数
- sgu172:eXam(二分图染色)
- 队列
- java web中过滤器的配置