这周事情比较多,所以只能用双休日来准备这个(3)了.
我们直入正体吧.
1.说明MessageQueue.cpp
2.简单描述一下目前状态下相关对象的关系
3 设计的逻辑结构
4.Visual Assist X
#include
"
MessageQueue.h
"

#include
<
memory.h
>

//在队列中加入一个新的消息节点
int
CMessageQueue::AddMessage(CMessage
*
msg)
{
MESSAGE *message = new MESSAGE; //新节点
message->msg = msg;
message->next = NULL;

if(this->_msgCount == 0) //设置队列的头指针,尾指针
{
this->_msgHead = message;
}
else
{
this->_msgTail->next = message;
}
this->_msgTail = message;
this->_msgCount++; //修正队列中的节点计数

return this->_msgCount;
}

//从队列头取出一个消息
int
CMessageQueue::PopMessage(CMessage
*
msg)
{
MESSAGE *message = NULL;

if(this->_msgCount <= 0)
{
return 0;
}

msg->Type = this->_msgHead->msg->Type; //复制队列头节点
msg->Length = this->_msgHead->msg->Length;
msg->Time = this->_msgHead->msg->Time;
msg->Data = new char[msg->Length];
msg->NetInfo.ip = this->_msgHead->msg->NetInfo.ip;
msg->NetInfo.port = this->_msgHead->msg->NetInfo.port;
memcpy(msg->Data, this->_msgHead->msg->Data, this->_msgHead->msg->Length);

message = this->_msgHead; //移除队列节点
this->_msgHead = this->_msgHead->next;

delete message->msg; //和AddMessage中的new操作相对应
message->msg = NULL;
delete message;
message = NULL;

this->_msgCount--;

if(this->_msgCount == 0)
{
this->_msgTail = NULL;
}

return (this->_msgCount + 1);
}

//构造一个空的队列
CMessageQueue::CMessageQueue()
{
this->_msgCount = 0;
this->_msgTail = this->_msgHead = NULL;
}

//析构一个队列,释放队列占有的资源
CMessageQueue::
~
CMessageQueue()
{
MESSAGE *pMsg = NULL;

if(this->_msgCount > 0)
{
while(this->_msgHead != NULL)
{
pMsg = this->_msgHead;
this->_msgHead = this->_msgHead->next;
delete pMsg->msg;
pMsg->msg = NULL;
pMsg->next = NULL;
delete pMsg;
}
}
}
我们直入正体吧.
1.说明MessageQueue.cpp
2.简单描述一下目前状态下相关对象的关系
3 设计的逻辑结构
4.Visual Assist X
1.MessageQueue.cpp
这个队列在目前实际测试的时候发现存在 线程安全问题, 这将在稍后的文章中加以修改, 后面就当前的情况加以说明.
#include
"
MessageQueue.h
"

#include
<
memory.h
>

//在队列中加入一个新的消息节点
int
CMessageQueue::AddMessage(CMessage
*
msg)
{
MESSAGE *message = new MESSAGE; //新节点
message->msg = msg;
message->next = NULL;
if(this->_msgCount == 0) //设置队列的头指针,尾指针
{
this->_msgHead = message;
}
else
{
this->_msgTail->next = message;
}
this->_msgTail = message;
this->_msgCount++; //修正队列中的节点计数
return this->_msgCount;
}

//从队列头取出一个消息
int
CMessageQueue::PopMessage(CMessage
*
msg)
{
MESSAGE *message = NULL;
if(this->_msgCount <= 0)
{
return 0;
}
msg->Type = this->_msgHead->msg->Type; //复制队列头节点
msg->Length = this->_msgHead->msg->Length;
msg->Time = this->_msgHead->msg->Time;
msg->Data = new char[msg->Length];
msg->NetInfo.ip = this->_msgHead->msg->NetInfo.ip;
msg->NetInfo.port = this->_msgHead->msg->NetInfo.port;
memcpy(msg->Data, this->_msgHead->msg->Data, this->_msgHead->msg->Length);
message = this->_msgHead; //移除队列节点
this->_msgHead = this->_msgHead->next;
delete message->msg; //和AddMessage中的new操作相对应
message->msg = NULL;
delete message;
message = NULL;
this->_msgCount--;
if(this->_msgCount == 0)
{
this->_msgTail = NULL;
}
return (this->_msgCount + 1);
}

//构造一个空的队列
CMessageQueue::CMessageQueue()
{
this->_msgCount = 0;
this->_msgTail = this->_msgHead = NULL;
}

//析构一个队列,释放队列占有的资源
CMessageQueue::
~
CMessageQueue()
{
MESSAGE *pMsg = NULL;
if(this->_msgCount > 0)
{
while(this->_msgHead != NULL)
{
pMsg = this->_msgHead;
this->_msgHead = this->_msgHead->next;
delete pMsg->msg;
pMsg->msg = NULL;
pMsg->next = NULL;
delete pMsg;
}
}
}
如果对"队列", "线程"等其他任何不理解的概念,请在CSDN.net中查找
没办法了, 我必须上传一个图片了.
图1:现有消息结构关系
3.1 网络
使用UDP这种"无连接"的方式来传输数据, 同时也便于稍后增加"P2P"的通信方式
3.2 消息
服务端监听设定的端口PORT, 将收到的合法信息Parse(解析)成设定的CMessage对象, 通过AddMessage加入CMessageQueue对象中
服务端维持一个MessageDispatcher线程, 负责处理从MessageQueue中PopMessage出来的Message,做出相应的处理.(<2>中已经说明了现有各个消息的格式)
3.3 数据
目前没有把各种消息存储下来,没有使用数据库,没有维护可固定的客户端列表, 暂时只是一个游戏服务端的原型, 后续文章将逐渐完善这一切, 也希望能获得读者们-也许就是你的支持.
客户端目前非常简单, 没有UI, 暂时相当于只用来测试服务端的功能, 以上消息处理完成,再加上 网络通信, 在线程处理不出错的情况下, 已经可以实现两个客户端之间的Text Message通信了.
客户端可以在此处下载查看,并且内有操作命令格式说明.
下载客户端
<5>开始就设计网络连接了
2.对象关系
到目前为止,我们出现了CMessage,CMessageQueue,MESSAGE_TYPE,NET_INFO等结构,下面我们就开始描述一下这些结构的关系. 至此我发现这个连载的顺序似乎需要调整,但是~~,还是继续吧.不过既然你看到这里了,相比接受了我的这个小小失误,而我也保证不再犯这样的错误,OK, 我们继续吧没办法了, 我必须上传一个图片了.
图1:现有消息结构关系
3.设计/想法
目前想法是这样的, TankServer是一个负责消息中转的服务端程序, 负责中转来自客户端的各种消息,同步客户端状态,用户列表.3.1 网络
使用UDP这种"无连接"的方式来传输数据, 同时也便于稍后增加"P2P"的通信方式
3.2 消息
服务端监听设定的端口PORT, 将收到的合法信息Parse(解析)成设定的CMessage对象, 通过AddMessage加入CMessageQueue对象中
服务端维持一个MessageDispatcher线程, 负责处理从MessageQueue中PopMessage出来的Message,做出相应的处理.(<2>中已经说明了现有各个消息的格式)
3.3 数据
目前没有把各种消息存储下来,没有使用数据库,没有维护可固定的客户端列表, 暂时只是一个游戏服务端的原型, 后续文章将逐渐完善这一切, 也希望能获得读者们-也许就是你的支持.
客户端目前非常简单, 没有UI, 暂时相当于只用来测试服务端的功能, 以上消息处理完成,再加上 网络通信, 在线程处理不出错的情况下, 已经可以实现两个客户端之间的Text Message通信了.
客户端可以在此处下载查看,并且内有操作命令格式说明.
下载客户端
>login name
name不能为空 长度控制在 6-10之间
>logout accountid
accountid 不能为空 有效值为 0-7
>logout name
name 不能为空 长度控制在6-10之间
>msg accountid txt
accountid不能为空 有效值为 0-7(不能给自己发消息)
txt 长度控制在 1-20之间 不能为空
>msg * txt
*代表给所有人发送消息
txt长度控制在 1-20之间 不能为空
>list
列举已知的所有用户 包括accountid 和 名称, 每个一行
name不能为空 长度控制在 6-10之间
>logout accountid
accountid 不能为空 有效值为 0-7
>logout name
name 不能为空 长度控制在6-10之间
>msg accountid txt
accountid不能为空 有效值为 0-7(不能给自己发消息)
txt 长度控制在 1-20之间 不能为空
>msg * txt
*代表给所有人发送消息
txt长度控制在 1-20之间 不能为空
>list
列举已知的所有用户 包括accountid 和 名称, 每个一行
4.Visual Assist X
如果你使用的是Visual Studio 6的话,建议安装一个Visual Assist X, 会有很大的代码书写帮助.5.预告
<4>主要说明dispatcher如何处理<5>开始就设计网络连接了
本文详细介绍了TankServer中消息队列MessageQueue.cpp的设计与实现,包括线程安全问题及其实现逻辑。此外还概述了相关对象间的关系,并提出了基于UDP的网络通信设想。


被折叠的 条评论
为什么被折叠?



