socket始终都只能传递byte数组,因为TCP/IP协议的原因。
如果需要传递一个对象,那么需要将这个对象序列化,然后就可以转换成byte数组进行传输了。
目前我只能传输struct,并且每个成员变量都不能是很复杂的类型,比如List<>类型的就不可以了,因为在获取其非托管大小的时候会发生异常的。
在获取非托管大小的时候不会发生异常的类型除了int、float、double、string等这些基本类型之外,还有array这种类型,其实int []、string []这些数组,都是继承自array 的。
首先定义序列化struct
[Serializable()] struct CC { public string[] a1; public string[] a2; }
其次转换对象为byte []
private static byte[] rawSerialize(object obj) { int rawsize = Marshal.SizeOf(obj); IntPtr buffer = Marshal.AllocHGlobal(rawsize); Marshal.StructureToPtr(obj, buffer, false); byte[] rawdatas = new byte[rawsize]; Marshal.Copy(buffer, rawdatas, 0, rawsize); Marshal.FreeHGlobal(buffer); return rawdatas; }
接收端将接收到的数组转换为类型
private static object rawDeserialize
socket接收的时候,接收端 :
recve是在接收的时候添加数据的,类型是List
(代码没有经过多行的测试,只是recve.Count==1的情况通过,因为我还没有测试过太大的对象的传输)
//如果判断接收已经结束,那么可以开始下面的代码 byte[] newrecv = new byte[0]; int offset = 0; for (int i = 0; i < recve.Count; i++) { Array.Resize
另外关于 int bytesRead = handler.EndReceive(ar); 的理解:
bytesRead 为0的情况是只有在对方close了socket之后。如果是大于0,说明对方还没有close,有可能还有数据传输过来。如果是小于0,可能是有网络异常,如果这句话直接异常,那么情况就是,你仍然在监听对方的消息,但是对方突然中断了(非正常退出)。
其实EndReceive就是socket的receive的异步的阻塞语句。只有当socket的接收完毕或者接收数据超过你传的buffer的大小之后,EndReceive才会释放阻塞,并且将得到的字节数量返回给bytesRead。
using System.Runtime.InteropServices; 是 Marshal 的命名空间。
综述:
以上的代码实际上都是一无是处的,为什么?
如果是同一个进程中的通讯,你可以像上面那样些,但是如果是不同进程之间的话,你可以试试,绝对不能通过。
原因就是托管的资源问题。
socket传输很简单,我就不说了,而且也没有什么问题。
问题出现在转换对象为数组的时候,你建立的对象是一个托管对象,如果你没有使用正确的序列化,那么你得到的byte数组就是不正确的。
你将不正确的byte传输过去之后,再转换,你能转换成功吗?显然不能。
首先你要明白转换序列化的意义在什么地方。
转换序列化,其实就是找到托管资源的实际数据,然后将这些实际的数据转换为byte,这样转换的话,就是对的。
如果你不使用序列化,那么你的操作就是将托管资源转换为byte数组,那么这样转换的东西就不是真正的你需要的,你将这样的数据传输过去,是会引起不可预料的错误的。
具体这么样使用正确的序列化,有空的时候再研究吧。