天天看点

Socket开发之通讯协议及处理

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

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

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

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

如下面这个例子:

<col>

01

06 00

01 0f ef 87 56 34

协议类别

协议代码

数据长度

实际数据

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

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

Socket开发之通讯协议及处理

 1

Socket开发之通讯协议及处理

    public class Message

 2

Socket开发之通讯协议及处理

    {

 3

Socket开发之通讯协议及处理

        private byte _class;

 4

Socket开发之通讯协议及处理

        private byte _flag;

 5

Socket开发之通讯协议及处理

        private int _size;

 6

Socket开发之通讯协议及处理

        private byte[] _content;

 7

Socket开发之通讯协议及处理

 8

Socket开发之通讯协议及处理

        public byte[] Content

 9

Socket开发之通讯协议及处理

        {

10

Socket开发之通讯协议及处理

            get { return _content; }

11

Socket开发之通讯协议及处理

            set { _content = value; }

12

Socket开发之通讯协议及处理

        }

13

Socket开发之通讯协议及处理

14

Socket开发之通讯协议及处理

        public int Size

15

Socket开发之通讯协议及处理

16

Socket开发之通讯协议及处理

            get { return _size; }

17

Socket开发之通讯协议及处理

            set { _size = value; }

18

Socket开发之通讯协议及处理

19

Socket开发之通讯协议及处理

20

Socket开发之通讯协议及处理

        public byte Flag

21

Socket开发之通讯协议及处理

22

Socket开发之通讯协议及处理

            get { return _flag; }

23

Socket开发之通讯协议及处理

            set { _flag = value; }

24

Socket开发之通讯协议及处理

25

Socket开发之通讯协议及处理

26

Socket开发之通讯协议及处理

        public byte Class

27

Socket开发之通讯协议及处理

28

Socket开发之通讯协议及处理

            get { return _class; }

29

Socket开发之通讯协议及处理

            set { _class = value; }

30

Socket开发之通讯协议及处理

31

Socket开发之通讯协议及处理

32

Socket开发之通讯协议及处理

        public Message()

33

Socket开发之通讯协议及处理

34

Socket开发之通讯协议及处理

35

Socket开发之通讯协议及处理

36

Socket开发之通讯协议及处理

37

Socket开发之通讯协议及处理

        public Message(byte @class, byte flag, byte[] content)

38

Socket开发之通讯协议及处理

39

Socket开发之通讯协议及处理

            _class = @class;

40

Socket开发之通讯协议及处理

            _flag = flag;

41

Socket开发之通讯协议及处理

            _size = content.Length;

42

Socket开发之通讯协议及处理

            _content = content;

43

Socket开发之通讯协议及处理

44

Socket开发之通讯协议及处理

45

Socket开发之通讯协议及处理

        public byte[] ToBytes()

46

Socket开发之通讯协议及处理

47

Socket开发之通讯协议及处理

            byte[] _byte;

48

Socket开发之通讯协议及处理

            using (MemoryStream mem = new MemoryStream())

49

Socket开发之通讯协议及处理

            {

50

Socket开发之通讯协议及处理

                BinaryWriter writer = new BinaryWriter(mem);

51

Socket开发之通讯协议及处理

                writer.Write(_class);

52

Socket开发之通讯协议及处理

                writer.Write(_flag);

53

Socket开发之通讯协议及处理

                writer.Write(_size);

54

Socket开发之通讯协议及处理

                if (_size &gt; 0)

55

Socket开发之通讯协议及处理

                {

56

Socket开发之通讯协议及处理

                    writer.Write(_content);

57

Socket开发之通讯协议及处理

                }

58

Socket开发之通讯协议及处理

                _byte = mem.ToArray();

59

Socket开发之通讯协议及处理

                writer.Close();

60

Socket开发之通讯协议及处理

            }

61

Socket开发之通讯协议及处理

            return _byte;

62

Socket开发之通讯协议及处理

63

Socket开发之通讯协议及处理

64

Socket开发之通讯协议及处理

        public static Message FromBytes(byte[] Buffer)

65

Socket开发之通讯协议及处理

66

Socket开发之通讯协议及处理

            Message message = new Message();

67

Socket开发之通讯协议及处理

            using (MemoryStream mem = new MemoryStream(Buffer))

68

Socket开发之通讯协议及处理

69

Socket开发之通讯协议及处理

                BinaryReader reader = new BinaryReader(mem);

70

Socket开发之通讯协议及处理

                message._class = reader.ReadByte();

71

Socket开发之通讯协议及处理

                message._flag = reader.ReadByte();

72

Socket开发之通讯协议及处理

                message._size = reader.ReadInt32();

73

Socket开发之通讯协议及处理

                if (message._size &gt; 0)

74

Socket开发之通讯协议及处理

75

Socket开发之通讯协议及处理

                    message._content = reader.ReadBytes(message._size);

76

Socket开发之通讯协议及处理

77

Socket开发之通讯协议及处理

                reader.Close();

78

Socket开发之通讯协议及处理

79

Socket开发之通讯协议及处理

            return message;

80

Socket开发之通讯协议及处理

81

Socket开发之通讯协议及处理

82

Socket开发之通讯协议及处理

    }

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

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

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

Socket开发之通讯协议及处理

  1

Socket开发之通讯协议及处理

    public class MessageStream

  2

Socket开发之通讯协议及处理

  3

Socket开发之通讯协议及处理

        private byte[] _buffer;

  4

Socket开发之通讯协议及处理

        private int _position;

  5

Socket开发之通讯协议及处理

        private int _length;

  6

Socket开发之通讯协议及处理

        private int _capacity;

  7

Socket开发之通讯协议及处理

  8

Socket开发之通讯协议及处理

        public MessageStream()

  9

Socket开发之通讯协议及处理

 10

Socket开发之通讯协议及处理

            _buffer = new byte[0];

 11

Socket开发之通讯协议及处理

            _position = 0;

 12

Socket开发之通讯协议及处理

            _length = 0;

 13

Socket开发之通讯协议及处理

            _capacity = 0;

 14

Socket开发之通讯协议及处理

 15

Socket开发之通讯协议及处理

 16

Socket开发之通讯协议及处理

        private byte ReadByte()

 17

Socket开发之通讯协议及处理

 18

Socket开发之通讯协议及处理

            if (this._position &gt;= this._length)

 19

Socket开发之通讯协议及处理

 20

Socket开发之通讯协议及处理

                return 0;

 21

Socket开发之通讯协议及处理

 22

Socket开发之通讯协议及处理

            return this._buffer[this._position++];

 23

Socket开发之通讯协议及处理

 24

Socket开发之通讯协议及处理

 25

Socket开发之通讯协议及处理

        private int ReadInt()

 26

Socket开发之通讯协议及处理

 27

Socket开发之通讯协议及处理

            int num = this._position += 4;

 28

Socket开发之通讯协议及处理

            if (num &gt; this._length)

 29

Socket开发之通讯协议及处理

 30

Socket开发之通讯协议及处理

                this._position = this._length;

 31

Socket开发之通讯协议及处理

                return -1;

 32

Socket开发之通讯协议及处理

 33

Socket开发之通讯协议及处理

            return (((this._buffer[num - 4] | (this._buffer[num - 3] &lt;&lt; 8)) | (this._buffer[num - 2] &lt;&lt; 0x10)) | (this._buffer[num - 1] &lt;&lt; 0x18));

 34

Socket开发之通讯协议及处理

 35

Socket开发之通讯协议及处理

 36

Socket开发之通讯协议及处理

        private byte[] ReadBytes(int count)

 37

Socket开发之通讯协议及处理

 38

Socket开发之通讯协议及处理

            int num = this._length - this._position;

 39

Socket开发之通讯协议及处理

            if (num &gt; count)

 40

Socket开发之通讯协议及处理

 41

Socket开发之通讯协议及处理

                num = count;

 42

Socket开发之通讯协议及处理

 43

Socket开发之通讯协议及处理

            if (num &lt;= 0)

 44

Socket开发之通讯协议及处理

 45

Socket开发之通讯协议及处理

                return null;

 46

Socket开发之通讯协议及处理

 47

Socket开发之通讯协议及处理

            byte[] buffer = new byte[num];

 48

Socket开发之通讯协议及处理

            if (num &lt;= 8)

 49

Socket开发之通讯协议及处理

 50

Socket开发之通讯协议及处理

                int num2 = num;

 51

Socket开发之通讯协议及处理

                while (--num2 &gt;= 0)

 52

Socket开发之通讯协议及处理

 53

Socket开发之通讯协议及处理

                    buffer[num2] = this._buffer[this._position + num2];

 54

Socket开发之通讯协议及处理

 55

Socket开发之通讯协议及处理

 56

Socket开发之通讯协议及处理

            else

 57

Socket开发之通讯协议及处理

 58

Socket开发之通讯协议及处理

                Buffer.BlockCopy(this._buffer, this._position, buffer, 0, num);

 59

Socket开发之通讯协议及处理

 60

Socket开发之通讯协议及处理

            this._position += num;

 61

Socket开发之通讯协议及处理

            return buffer;

 62

Socket开发之通讯协议及处理

 63

Socket开发之通讯协议及处理

 64

Socket开发之通讯协议及处理

        public bool Read(out Message message)

 65

Socket开发之通讯协议及处理

 66

Socket开发之通讯协议及处理

            message = null;

 67

Socket开发之通讯协议及处理

 68

Socket开发之通讯协议及处理

            if (_length &gt; 6)

 69

Socket开发之通讯协议及处理

 70

Socket开发之通讯协议及处理

                message = new Message();

 71

Socket开发之通讯协议及处理

                message.Class = ReadByte();

 72

Socket开发之通讯协议及处理

                message.Flag = ReadByte();

 73

Socket开发之通讯协议及处理

                message.Size = ReadInt();

 74

Socket开发之通讯协议及处理

                if (message.Size &lt;= 0 || message.Size &lt;= _length - _position)

 75

Socket开发之通讯协议及处理

 76

Socket开发之通讯协议及处理

                    if (message.Size &gt; 0)

 77

Socket开发之通讯协议及处理

                    {

 78

Socket开发之通讯协议及处理

                        message.Content = ReadBytes(message.Size);

 79

Socket开发之通讯协议及处理

                    }

 80

Socket开发之通讯协议及处理

                    Remove(message.Size + 6);

 81

Socket开发之通讯协议及处理

                    return true;

 82

Socket开发之通讯协议及处理

 83

Socket开发之通讯协议及处理

                else

 84

Socket开发之通讯协议及处理

 85

Socket开发之通讯协议及处理

                    message = null;

 86

Socket开发之通讯协议及处理

                    return false;

 87

Socket开发之通讯协议及处理

 88

Socket开发之通讯协议及处理

 89

Socket开发之通讯协议及处理

 90

Socket开发之通讯协议及处理

 91

Socket开发之通讯协议及处理

                return false;

 92

Socket开发之通讯协议及处理

 93

Socket开发之通讯协议及处理

 94

Socket开发之通讯协议及处理

 95

Socket开发之通讯协议及处理

        private void EnsureCapacity(int value)

 96

Socket开发之通讯协议及处理

 97

Socket开发之通讯协议及处理

            if (value &lt;= this._capacity)

 98

Socket开发之通讯协议及处理

                return;

 99

Socket开发之通讯协议及处理

            int num1 = value;

100

Socket开发之通讯协议及处理

            if (num1 &lt; 0x100)

101

Socket开发之通讯协议及处理

                num1 = 0x100;

102

Socket开发之通讯协议及处理

            if (num1 &lt; (this._capacity * 2))

103

Socket开发之通讯协议及处理

                num1 = this._capacity * 2;

104

Socket开发之通讯协议及处理

            byte[] buffer1 = new byte[num1];

105

Socket开发之通讯协议及处理

            if (this._length &gt; 0)

106

Socket开发之通讯协议及处理

                Buffer.BlockCopy(this._buffer, 0, buffer1, 0, this._length);

107

Socket开发之通讯协议及处理

            this._buffer = buffer1;

108

Socket开发之通讯协议及处理

            this._capacity = num1;

109

Socket开发之通讯协议及处理

110

Socket开发之通讯协议及处理

111

Socket开发之通讯协议及处理

        public void Write(byte[] buffer, int offset, int count)

112

Socket开发之通讯协议及处理

113

Socket开发之通讯协议及处理

            if (buffer.Length - offset &lt; count)

114

Socket开发之通讯协议及处理

115

Socket开发之通讯协议及处理

                count = buffer.Length - offset;

116

Socket开发之通讯协议及处理

117

Socket开发之通讯协议及处理

            EnsureCapacity(buffer.Length + count);

118

Socket开发之通讯协议及处理

            Array.Clear(_buffer, _length, _capacity - _length);

119

Socket开发之通讯协议及处理

            Buffer.BlockCopy(buffer, offset, _buffer, _length, count);

120

Socket开发之通讯协议及处理

            _length += count;

121

Socket开发之通讯协议及处理

122

Socket开发之通讯协议及处理

123

Socket开发之通讯协议及处理

        private void Remove(int count)

124

Socket开发之通讯协议及处理

125

Socket开发之通讯协议及处理

            if (_length &gt;= count)

126

Socket开发之通讯协议及处理

127

Socket开发之通讯协议及处理

                Buffer.BlockCopy(_buffer, count, _buffer, 0, _length - count);

128

Socket开发之通讯协议及处理

                _length -= count;

129

Socket开发之通讯协议及处理

                Array.Clear(_buffer, _length, _capacity - _length);

130

Socket开发之通讯协议及处理

131

Socket开发之通讯协议及处理

132

Socket开发之通讯协议及处理

133

Socket开发之通讯协议及处理

                _length = 0;

134

Socket开发之通讯协议及处理

                Array.Clear(_buffer, 0, _capacity);

135

Socket开发之通讯协议及处理

136

Socket开发之通讯协议及处理

137

Socket开发之通讯协议及处理

这个类的使用非常简单,你只要用Write(byte[] buffer,int offset, int count)将接收到的数据写入数据流中,并用bool

Read(out Message message)将数据中的第一个数据包取出,如果函数返回True,就说明取回一个封包成功,如果返回False,则说明流中已经没有完整的封包,你需要继续接收后面的数据以组成一个完整的封包。

这们我们的数据分析就会变得非常简单。我们可以在ReceiveCallBack回调函数中将接收到的数据写入到流中并通知线程池中的工作者线程分析数据流并处理数据。我在前面的关于Socket异步操作的文章中的Analyzer函数就是用这两个类来分析处理数据的。这样的好处理就是,Socket工作线程只需要负责数据的接收,并将其写入流,其它的事情由其它的线程这处理,就不会因为处理的时间过长而导致接收操作被阻塞。从而影响Socket的性能。

本文所述方法只是协议处理的多种方法中的其中一种,而且可能并不是很优秀的方法,如果谁有更好的方法,还希望您能和我多多交流。好了,今天就到这里了,关于Socket的文章到这里可能就告一段落了,我现在在研究VS2008里面的新东西,如果有什么必得的话,我会继续写出来的。谢谢大家的支持。