zoukankan      html  css  js  c++  java
  • 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!房子啥时候装好?我急嫁人啊!

  • 相关阅读:
    oracle与DB2
    oracle ORA-01427: 单行子查询返回多个行
    mysql开发总结
    mysql show profile基本详解
    mysql批量插入数据
    mysql索引详解
    mysql性能调优
    MySQL优化
    mysql主从调优
    mysql主从复制
  • 原文地址:https://www.cnblogs.com/wangergo/p/1708879.html
Copyright © 2011-2022 走看看