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

虽然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_message
void 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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值