[网络]Unity的Socket通讯_2_数据传输

15 篇文章 0 订阅

好了,已经连上服务器了,可是怎么通信,,,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
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值