Silverlight MMORPG WebGame游戏设计(三)-----Server和Client的暗号

          silverlight客户端和服务端就像一对被微软家长阻隔的恋人,服务端提供了安全策略文件这个硬通货,就如同男人买了房,一切都开绿灯了。

          这对恋人终于可以约会了,他们如何飞鸿传书呢?是写在枫叶上,还是封上了火漆的羊皮卷里。其实每个民族有自己的风俗,每个程序员也可以写出不同的协议。

          我们把他们通讯的基本单位抽象成Message,你可以这么描述它:

         

Message类
  public class Message
    {

     /// <summary>
        /// 处理信息的socket对象
        /// </summary>
        public System.Net.Sockets.Socket clientSocket { get; set; }
        /// <summary>
        /// 消息内容
        /// </summary>
        public byte[] Content{get;set;}
        /// <summary>
        /// 消息长度
        /// </summary>
        public int Size{get;set;}
        /// <summary>
        /// 消息状态
        /// </summary>
        public byte Flag{get;set;}
        /// <summary>
        /// 消息类别
        /// </summary>
        public byte Class {get;set;}
    
   }

       也就是说服务端和客户端通讯的时候是一个个message为单位发送过去的,但是传输过程中,服务端不可能刚好完整就接到了一个Message,也可能接收到半个Message,所以需要加一个size来判断是否Message读取完毕。

       在封装Message的时候我们要写一个MessageStream类来方便封装Message,一般网络游戏服务端和客户端都会有这样的类,来从byte数组中把数据读出,或者把数据写入到byte数组中,这样的类里一般都有ReadInt,ReadByte,ReadString,ReadFloat,WriteInt,WriteByte , WriteString,WriteFloat 这样的方法。

       这里我给出一个很简单的封装类MessageStream

       

MessageStream
   public class MessageStream
    {
        
private byte[] buffer;
        
private int position;
        
private int length;
        
private int capacity;

        
public MessageStream()
        {
            buffer 
= new byte[0];
            position 
= 0;
            length 
= 0;
            capacity 
= 0;
        }

        
private byte ReadByte()
        {
            
if (this.position >= this.length)
            {
                
return 0;
            }
            
return this.buffer[this.position++];
        }

        
private int ReadInt()
        {
            
int num = this.position += 4;
            
if (num > this.length)
            {
                
this.position = this.length;
                
return -1;
            }
            
return (((this.buffer[num - 4| (this.buffer[num - 3<< 8)) | (this.buffer[num - 2<< 0x10)) | (this.buffer[num - 1<< 0x18));
        }

        
private byte[] ReadBytes(int count)
        {
            
int num = this.length - this.position;
            
if (num > count)
            {
                num 
= count;
            }
            
if (num <= 0)
            {
                
return null;
            }
            
byte[] buffer = new byte[num];
            
if (num <= 8)
            {
                
int num2 = num;
                
while (--num2 >= 0)
                {
                    buffer[num2] 
= this.buffer[this.position + num2];
                }
            }
            
else
            {
                Buffer.BlockCopy(
this.buffer, this.position, buffer, 0, num);
            }
            
this.position += num;
            
return buffer;
        }

        
public bool Read(out Message message)
        {
            message 
= null;
            position 
= 0;
            
if (length > 6)
            {
                message 
= new Message();
                message.Class 
= ReadByte();
                message.Flag 
= ReadByte();
                message.Size 
= ReadInt();
                
if (message.Size <= 0 || message.Size <= length - position)
                {
                    
if (message.Size > 0)
                    {
                        message.Content 
= ReadBytes(message.Size);
                    }
                    Remove(message.Size 
+ 6);
                    
return true;
                }
                
else
                {
                    message 
= null;
                    
return false;
                }
            }
            
else
            {
                
return false;
            }
        }
         
        
private void EnsureCapacity(int value)
        {
            
if (value <= this.capacity)
                
return;
            
int num1 = value;
            
if (num1 < 0x100)
                num1 
= 0x100;
            
if (num1 < (this.capacity * 2))
                num1 
= this.capacity * 2;
            
byte[] buffer1 = new byte[num1];
            
if (this.length > 0)
                Buffer.BlockCopy(
this.buffer, 0, buffer1, 0this.length);
            
this.buffer = buffer1;
            
this.capacity = num1;
        }

          public void Write(byte[] intbuffer, int offset, int count)
        {
            if (intbuffer.Length - offset < count)
            {
                count = intbuffer.Length - offset;
            }
            EnsureCapacity(length + count);
            Array.Clear(this.buffer, length, capacity - length);
            Buffer.BlockCopy(intbuffer, offset, this.buffer, length, count);
            length += count;
        }
        private void Remove(int count)
        {
            
if (length >= count)
            {
                Buffer.BlockCopy(buffer, count, buffer, 
0, length - count);
                length 
-= count;
                Array.Clear(buffer, length, capacity 
- length);
            }
            
else
            {
                length 
= 0;
                Array.Clear(buffer, 
0, capacity);
            }
        }
    }

 

 

      有了MessageStream这样的辅助类了,我们就可以在Message类加上一个添加消息和一个读取消息的方法

    

写入和读取Message的方法
   /// <summary>
        
/// 把消息对象转化为byte[]
        
/// </summary>
        
/// <returns></returns>
        public byte[] ToBytes()
        {
            
byte[] _byte;
            
using (MemoryStream mem = new MemoryStream())
            {
                BinaryWriter writer 
= new BinaryWriter(mem);
                writer.Write(Class);
                writer.Write(Flag);
                writer.Write(Size);
                
if (Size > 0)
                {
                    writer.Write(Content);
                }
                _byte 
= mem.ToArray();
                writer.Close();
            }
            
return _byte;
        }
        
/// <summary>
        
/// 从byte[]中读取一个message对象
        
/// </summary>
        
/// <param name="Buffer"></param>
        
/// <returns></returns>
        public static Message FromBytes(byte[] Buffer)
        {
            Message message 
= new Message();
            
using (MemoryStream mem = new MemoryStream(Buffer))
            {
                BinaryReader reader 
= new BinaryReader(mem);
                message.Class 
= reader.ReadByte();
                message.Flag 
= reader.ReadByte();
                message.Size 
= reader.ReadInt32();
                
if (message.Size > 0)
                {
                    message.Content 
= reader.ReadBytes(message.Size);
                }
                reader.Close();
            }
            
return message;
        }

 

         有了MessageStream,Message这两个忠实的仆人的帮助,SL客户端和服务端这对恋人就不用像发摩尔斯电码那样来交流了,他们只要口述旨意,让两个仆人去滴滴答答发电报就行了。见过电影里发电报的都知道,有人发电报,就有人收电报。所以客户端有这样两个仆人,服务端也得有这样两个仆人。那我们程序员的话说SL客户端有这样两个类,同样服务端也要有这样两个类。

        当然以上我只是简单描述了一个Message对象,在真实项目里Message对象没这么简单。我举个例子:

       

格式:

循环

循环

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

不定长

消息个数

消息总长度

用户UID

用户CID

单个消息指针起始位置

消息内容

消息内容协议

0

1

2

3

4

5

不定长

消息Group

消息具体type

时间戳

消息逻辑内容

 

 HTTP命令区:

       Message1 (byte) 消息个数

       MessageLength: 120 (int) byte数组总长度

       UID:2 (int)用户标识ID

       CID 1 (int)用户子ID

       MessagePointer: 0 (short) 单个消息指针起始位置

HTTP 内容区:

       GroupID:1 (byte) 消息组ID

       GroupType:1 (byte) 消息组具体操作ID

       Timestamp: 0 (int) 时间戳

       ContentLength: 10 (short) 消息内容的长度(根据内容来定类型)

Content:”你好吗?” (string) 消息内容

    这种协议一次可以发多个消息体,只带一个消息头,也带上用户的信息,因为mmorpg里参与最多是用户,发的消息也和用户编号直接相关。

     有兴趣的同学可以写下这个种协议的写入和读取。到此为止,是不是服务端和客户端就可以踏入婚姻的殿堂了,可惜还远没有呢,这是各自准备了两个伴郎和伴娘,客户端急了:“老公,你房子什么时候才装修好啊?”

      大家看到这里也在想,服务端什么时候才可以搭建好啊,就像装房子一样,急不得,还有好多问题。请看下一篇:

      Silverlight MMORG WebGame游戏设计(四)-----Client:Server!房子啥时候装好?我急嫁人啊!

posted @ 2010-04-10 12:52  王传炜  阅读(2810)  评论(10编辑  收藏  举报