licongjie的博客

专心、专注、专业
随笔 - 26, 文章 - 1, 评论 - 207, 引用 - 5
数据加载中……

Socket网络编程学习笔记(5):发送和接收实体类数据

      在前面讲述的篇幅中,发送的都是文本信息,我们只要通过Encoding中的几个方法把文本转化成二进制数组就可以利用Socket来传输了,这对于一些基本的信息传输能够得到满足,但对于一些复杂的消息交流,则有些“吃力”。我们有时候会把一些信息封闭在一个类中,如果Socket能够传送类对象,那么一些复杂的问题能够通过面向对象来解决了,即方便又安全。大家都知道,要想在网络上传输信息,必须要经过序列化才行,所以在传送类对象时,首选必须对该类对象进行序列化,才能够在网络上进行传输。

      序列化类对象有三种序列化方法:

      1、Xml序列化

      2、Binary序列化

      3、Soap序列化

      这几种序列化方法,运用方法相类似,只不过用到的类不一样。在这里也不一一讲述了,有兴趣的朋友可以到网上搜一搜,相信会有不少的收获。这里主要讲一下利用Soap序列化来传送消息。

      1、首先我们先来建立一个实体类,用来做消息的载体
类对象

      2、发送前先把类对象进行Soap序列化

消息发送方法


      这里利用 
            IFormatter formatter = new SoapFormatter();
            MemoryStream mem = new MemoryStream();

            formatter.Serialize(mem, sd);
      对类对象sd进行序列化。在这里还有一个细节值得一提,那就是消息边界问题的处理,这里是利用发送消息的长度方法来实现。代码如下:

1int memsize = (int)mem.Length;
2            byte[] size = BitConverter.GetBytes(memsize);
3            ns.Write(size, 04);

      通过BitConverter.GetBytes()方法可以把数据类型转化为二进制数组,从而可以在网络上传送,所以在接收的时候先接收消息长度,再通过该长度来循环读取完整的消息。

      3、接收消息
接收消息方法

      通过sd = (SocketData)formatter.Deserialize(mem);还原数据为类对象,就可以对此类对象进行访问了。用Xml序列化或用二进制序列化也是类似,只不过把序列化的方法改一下就可以了,一般来说用二进制序列化得到的数据最小,占用带宽也最小,而用xml和Soap来序列化,都是序列化为Xml格式,所以数据比较大,占用带宽比较大。但用xml或Soap序列化,兼容性高,可以兼容不同系统之间的通信,而二进制不行。可以说各有利弊,可以根据实际情况来选择哪一种序列化。

      该篇暂时就写到这里了,文字有点乱,请见谅。

源码下载:/Files/licongjie/SocketTest4.rar
      

posted on 2006-10-27 16:59 李.net 阅读(2884) 评论(17)  编辑 收藏 所属分类: Socket编程

评论

#1楼    回复  引用    

楼主讲的很明白,我今天才明白了什么叫序列化,呵呵

#2楼    回复  引用    

请教一下, revc = ns.Read(data, 0, size);
为什么不写成revc=ns.Read(data,offset,size)

#3楼 [楼主]   回复  引用  查看    

@wenjie[匿名]
呵呵,这个地方好象打错了,应该是offset ,这里由于发送的数据量不是很大,所以一次性就能读取完毕,也没有出现错误。现已改正,不过代码就不再重新上传了,各位看了自己清楚就是了
2006-10-28 21:09 | 李.net      

#4楼    回复  引用    

收到,谢谢

#5楼    回复  引用  查看    

现在有种JSON方式,据说比XML方式效率要高一些
2006-10-29 11:58 | 兰亭      

#6楼 [楼主]   回复  引用  查看    

@wenjie[匿名]
呵呵,不客气,谢谢指正
2006-10-29 14:10 | 李.net      

#7楼 [楼主]   回复  引用  查看    

@兰亭
是吗,这个我到没有去注意过,不知道有没有相关的文档链接
2006-10-29 14:10 | 李.net      

#8楼    回复  引用    

JSON主要用于Ajax吧

#9楼    回复  引用    

请教一下:

在SocketUtility类中的Receive方法使用了一个while循环接收
数据,而Send方法中发送数据时写入NetworkStream时并没有使用while循环,
请教一下,是NetworkStream类本身实现了么

#10楼    回复  引用  查看    

在这段代码中:
while (size > 0)
{
data = new byte[1024];
revc = ns.Read(data, offset, size);
mem.Write(data, offset, revc);
offset += revc;
size -= revc;
}
假设size=2000,循环不会报错?
2006-10-31 14:07 | IORICC      

#11楼 [楼主]   回复  引用  查看    

@wenjie[匿名]
那是因为在发送的时候,通过networkstream可以把数据发送到缓存中去,如ns.Write(data, 0, memsize);这里我们可以很容易的知道要发送数据的大小,可以一次性发送完毕,不用再循环发送了,当然最后你也可以用ns.flush();把要发送的数据全部发送到缓存中。而接收的时候,虽然也可以一开始接收到要接收数据的长度,但存在一定的网络问题,有可能我去读数据的时候,只有数据的一部分在缓存里,那么就只能读取这么一部分了,如果不用循环用size -= revc;该语句来检查收到的数据长度跟数据的实际长度是否一样的话,那么很容易导致数据的不完整性,当然如果你在自己的机子上测试的话,根本不存在这样的问题,但如果进行分布式分布的话,特别如果分布在外网上,这种情况不见得不会发生。

不知道这样解释行不行得通,知识有限,请见谅
2006-10-31 17:54 | 李.net      

#12楼 [楼主]   回复  引用  查看    

@IORICC
老实说我没有测试过,但我想通过revc = ns.Read(data, offset, size); 返回的revc是接收到的数据的长度,再通过 offset += revc; size -= revc; 这二句,改变循环变量和偏 移量,当数据大于1024时,也可以完全通过循环来接收的。

这样说好象缺少实践性,有空的时候测试一下!
2006-10-31 17:58 | 李.net      

#13楼    回复  引用    

非常感谢

#14楼    回复  引用  查看    

当size>1024,程序应该保存吧?
2007-01-30 17:46 | 海纳百川      

#15楼    回复  引用    

good
2007-04-25 17:41 | sunny [未注册用户]

#16楼    回复  引用  查看    

很好,回过头来再请教
2007-11-06 17:38 | lastgame      

#17楼    回复  引用    

您好,我用这种方法发送如果是一条一条的发没有问题,但我用多个客户端(发送消息时用线程发送)同时发送时在服务端反序列时报错.

输入流是无效的二进制格式。开始内容(以字节为单位)
是: 33-35-36-32-34-06-06-00-00-00-13-32-30-30-37-2D-31...
2007-12-21 11:55 | lem12 [未注册用户]