Asp.Net教程,WinForm教程,Asp.Net MVC,vs2008教程,vs2010教程,Silverlight技术,源码下载,Asp.Net视频教程
全站热门标签
vs2010 Silverlight 存储过程 水晶报表 ADO.NET JavaScript LINQ AjaxPro DataGridView 面向对象 Extjs GridView XML DevExpress HTML教程 Oracle jQuery 分页 GDI+ Visual C++2010 MySQL Office2010 WPF MVC Dojo WCF4.0 VB.NET Sql2005 textbox cookie WCF WinForm Discuz!NT SQL经典语句 T-SQL checkbox ASPxGridView F# asp.net SQL VS2008新特性 DropDownList Access TreeView Ajax VS2008 页面执行时间 Flex 字符串 回调 VB2005 DataSet C#时间 ASP.NET性能优化 用户在线检测 动画
FrameworkC#技术 VB.NET VC.NET WCF WPF
当前位置: 主页 > WinForm教程 > C#技术 >

Socket开发之通讯协议及处理

时间:2010-08-31 23:33来源:未知 作者:admin 点击:

Socket应用开发中,还有一个话题是讨论的比较多的,那就是数据接收后如何处理的问题。这也是一个令刚接触Socket开发的人很头疼的问题。

因为SocketTCP通讯中有一个“粘包”的现象,既:大多数时候发送端多次发送的小数据包会被连在一起被接收端同时接收到,多个小包被组成一个大包被接收。有时候一个大数据包又会被拆成多个小数据包发送。这样就存在一个将数据包拆分和重新组合的问题。那么如何去处理这个问题呢?这就是我今天要讲的通讯协议。

所谓的协议就是通讯双方协商并制定好要传送的数据的结构与格式。并按制定好的格式去组合与分析数据。从而使数据得以被准确的理解和处理。

那么我们如何去制定通讯协议呢?很简单,就是指定数据中各个字节所代表的意义。比如说:第一位代表封包头,第二位代表封类型,第三、四位代表封包的数据长度。然后后面是实际的数据内容。

如下面这个例子:

01

01

06 00

01 0f ef 87 56 34

协议类别

协议代码

数据长度

实际数据

前面三部分称之为封包头,它的长度是固定的,第四部分是封包数据,它的长度是不固定的,由第三部分标识其长度。因为我们的协议将用在TCP中,所以我没有加入校验位。原因是TCP可以保证数据的完整性。校验位是没有必要存在的。

接下来我们要为这个数据封包声明一个类来封装它:

public class Message
 2    {
 3        private byte _class;
 4        private byte _flag;
 5        private int _size;
 6        private byte[] _content;
 7
 8        public byte[] Content
 9        {
10            get { return _content; }
11            set { _content = value; }
12        }
13
14        public int Size
15        {
16            get { return _size; }
17            set { _size = value; }
18        }
19
20        public byte Flag
21        {
22            get { return _flag; }
23            set { _flag = value; }
24        }
25
26        public byte Class
27        {
28            get { return _class; }
29            set { _class = value; }
30        }
31
32        public Message()
33        {
34
35        }
36
37        public Message(byte @class, byte flag, byte[] content)
38        {
39            _class = @class;
40            _flag = flag;
41            _size = content.Length;
42            _content = content;
43        }
44
45        public byte[] ToBytes()
46        {
47            byte[] _byte;
48            using (MemoryStream mem = new MemoryStream())
49            {
50                BinaryWriter writer = new BinaryWriter(mem);
51                writer.Write(_class);
52                writer.Write(_flag);
53                writer.Write(_size);
54                if (_size > 0)
55                {
56                    writer.Write(_content);
57                }
58                _byte = mem.ToArray();
59                writer.Close();
60            }
61            return _byte;
62        }
63
64        public static Message FromBytes(byte[] Buffer)
65        {
66            Message message = new Message();
67            using (MemoryStream mem = new MemoryStream(Buffer))
68            {
69                BinaryReader reader = new BinaryReader(mem);
70                message._class = reader.ReadByte();
71                message._flag = reader.ReadByte();
72                message._size = reader.ReadInt32();
73                if (message._size > 0)
74                {
75                    message._content = reader.ReadBytes(message._size);
76                }
77                reader.Close();
78            }
79            return message;
80        }
 

我们可以用Tobytes()FromBytes()将封包转换成二进制数组和从二进制数组转换回来。

事情看起来已经解决了,但……真的是这样子吗?不然,我们知道,TCP数据是以流的形式被传送的,我们并不知道一个数据包是否被传送完毕,也不知道我们接收回来的数据包中是否有多个数据包,如果直接使用FromBytes()来转换的话,很可能会因为数据不完整而出现异常,也有可能会因为数据中含有多个数据包而导致数据丢失(因为你并不知道这些数据中含有多少个数据包)。那我们该怎么办?这也不难,我们先把接收回来的数据写入一个流中。然后分析其中是否有完整的数据包,如果有,将其从流中取出,并将这部分数据从流中清除。直到流中没有完整的数据为止,以后接收回来的数据就将其写入流的结尾处,并从头继续分析。直到结束。

让我们来看看这部分的代码:

(责任编辑:admin)

Tags:Socket
责任编辑:admin
返回顶部
------分隔线----------------------------
推荐内容
骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价 骆驼户外男 真皮磨砂日常休闲鞋 低帮 2011秋冬新款 专柜正品特价