Unity的Socket通讯_2_数据传输

来源:互联网 发布:品茗软件客服电话 编辑:程序博客网 时间:2024/04/26 08:10

好了,已经连上服务器了,可是怎么通信,,,byte[]是个什么鬼?

好吧,来了解下数据转换吧,还记得刚学编程时,字符串转Int的Convert吗?

    public void Convert()    {        string str = "hello world";        byte[] strbyte = Encoding.UTF8.GetBytes(str);        Debug.Log(Encoding.UTF8.GetString(strbyte,0,strbyte.Length));        int n = 13;        byte[] nbyte = BitConverter.GetBytes(n);        Debug.Log(BitConverter.ToInt32(nbyte,0));    }

上面的就是两个常用的方法,第一个Encoding是编码类,里面有好多种编码,Utf8是万国码,你要想支持中文就得选这个。Ascii码学过汇编的都懂,就255个字符,中文指定不够用。

下面的BitConverter是值类型的转换,我是这么理解的,也没去查,说错就说错吧。

都知道string类型其实是个引用类型,说白了就是个对象,所以在转换的时候有三个参数,第一个是string,第二个是起始位置(内存的起始位置),第三个是长度(占用内存的长度)。

BitConverter呢,只需要知道起始位置就行了,因为值类型的长度是固定的。

关于Encoding和BitConverter的内容可以上msdn查阅,我也不或者点这里了。

那上一篇的代码,我们只需要在Receive中间加入一句代码

    private void Receive(IAsyncResult ar)    {        int size = client.EndReceive(ar);        //Debug.Log("收到数据" + size);        if (size < 1)        {            Debug.Log("服务器关闭");            closeConnect();            return;        }        Debug.Log(Encoding.UTF8.GetString(receiveData,0,size));//输出接受到的字符串        client.BeginReceive(receiveData, 0, receiveData.Length, SocketFlags.None, new AsyncCallback(Receive), null);    }

这样我们就能把服务器发送过来的字符串编译到本地了,然后继续等待.....

然后你会发现然而并没有什么卵用,,,

是的,我们不可能只传字符串,这连聊天室的功能都满足不了,我们要传的是数据,里面有各种各样的类型,变量等!!

    public static byte[] StructToBytes(object structObj)//结构体转byte[]    {        int size = Marshal.SizeOf(structObj);//获得结构体大小        byte[] bytes=new byte[size];        IntPtr structPtr = Marshal.AllocHGlobal(size);//从非托管内存中划片空间        Marshal.StructureToPtr(structObj,structPtr,false);//把结构体放到非托管内存中就变成byte[]了        Marshal.Copy(structPtr,bytes,0,size);//把bytes[]从内存中复制出来        Marshal.FreeHGlobal(structPtr);//清理内存        return bytes;//输出    }        public static object BytesToStruct(byte[] bytes,Type type)//byte[]转结构体    {        int size = Marshal.SizeOf(type);//获得结构体类型大小        if (size > bytes.Length)//类型大小比byte[]大,就跳出            return null;        IntPtr structPtr = Marshal.AllocHGlobal(size);//开辟空间        Marshal.Copy(bytes,0,structPtr,size);//复制到内存中        object obj = Marshal.PtrToStructure(structPtr, type);//从非托管内存中转换成对应类型的obj托管对象        Marshal.FreeHGlobal(structPtr);//清理内存        return obj;    }        [Serializable]//可被序列化        [StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]//整理内存布局        struct Person        {            public string name;            public int age;        }        public void Test()        {            Person P1 = new Person();            P1.name = "叶良辰";            P1.age = 250;            byte[] data = StructToBytes(P1);            Person P2 = (Person)BytesToStruct(data,typeof(Person));           Debug.Log("姓名:"+P2.name+"\n年龄:"+P2.age);        }

上面这个代码有些和网上的很象,没错,我就是抄的,啊,原文请点这里

序列化嘛,肯定的,设置内存布局,应该就是让这个结构体在内存中排列的规整点,我是这么猜的,说错就错了吧。

通过这段代码,我们可以把结构体转换成byte[],然后接受后再转换为对应的结构体(也可以转class),本地测试貌似没问题。

但实际上我在应用中遇到了很多问题,大部分问题出在这个托管与非托管上面,

托管就是有中间语言的,说白了.net执行的代码,非托管,就没中间语言了,系统直接执行的。

具体报什么错我忘了,毕竟好早以前的事了。

而且再看写法,发现很繁琐。

有没有不整什么托管非托管,内存不内存的1,2行代码就搞定的。

还真有,还记得struct上面的[Serializable]吗,Serializable特性,对,直接序列化就行了,好傻啊,简直是饶了一大弯。

        public static byte[] ObjectToByte(object obj)//序列化        {            using (MemoryStream ms = new MemoryStream())//申请流内存,结束自动收回            {                BinaryFormatter bf = new BinaryFormatter();                bf.Serialize(ms, obj);//序列化                return ms.GetBuffer();//取出byte[]            }        }        public static object ByteToObject(byte[] data)//反序列化        {            using (MemoryStream ms = new MemoryStream(data))            {                BinaryFormatter bf = new BinaryFormatter();                return bf.Deserialize(ms);//反序列化            }        }        [Serializable]//可被序列化        struct Person        {            public string name;            public int age;        }        public void Test()        {            Person P1 = new Person();            P1.name = "叶良辰";            P1.age = 250;            byte[] data = ObjectToByte(P1);            Person P2 = (Person)ByteToObject(data);            Debug.Log("姓名:" + P2.name + "\n年龄:" + P2.age);        }
现在看这两个转换方法,是不是很简洁,两行代码搞定,而且反序列化也不需要知道什么类型,

最最重要的根本不用考虑什么托管与非托管,想干啥就干啥。

这样我们就可以随心所欲的在服务器和客户端之间传递任何数据了,当然,服务端必须是C#写的。

服务端是其他语言写的,目前还没研究过,等接触了再补篇吧。

关于序列化的详细内容请自行百度。

0 0