socket 的链接粘包的问题

---恢复内容开始---

 前边两个是服务器的 

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace Socket1
 8 {
 9     class Message
10     {
11         private byte[] data = new byte[1024];
12         private int starIndex = 0;//剩余长度
13 
14         public byte[] Data { get => data; set => data = value; }
15         public int StarIndex { get => starIndex; set => starIndex = value; }
16 
17         public int RemainSize//剩余空间大小
18         {
19             get { return data.Length - starIndex; }
20         }
21         public void AddCount(int count)//每次得到新的数据 就更新StartIndex
22         {
23             starIndex += count;
24         }
25 
26         public void ReadMassage()
27         {
28             while (true)
29             {
30                 if (StarIndex<=4)
31                 {
32                     return;
33                 }
34                 int count = BitConverter.ToInt32(data, 0);//第一段数据的长度
35                 if (StarIndex-4>=count)
36                 {
37                     string s= Encoding.UTF8.GetString(data,4,count);
38                     Console.WriteLine("解析到一条数据"+s);
39 
40                     Array.Copy(data,count+4,data,0,StarIndex-4-count);
41                     StarIndex -= (count + 4);
42                 }
43                 else
44                 {
45                     break;
46                 }
47             }
48         }
49     }
50 }
Message文件里的
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Net;
 5 using System.Net.Sockets;
 6 using System.Text;
 7 using System.Threading.Tasks;
 8 
 9 
10 namespace Socket1
11 {
12     class Program
13     {
14         static void Main(string[] args)
15         {
16             StartServer();
17             Console.ReadKey();
18         }
19         static void StartServer()
20         {
21             Socket server = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
22             IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
23             IPEndPoint iPEndPoint = new IPEndPoint(ipAddress,1234);
24             server.Bind(iPEndPoint);
25 
26             server.Listen(0);//开始监听
27 
28             //Socket clientSocket= server.Accept();
29 
30             server.BeginAccept(AcceptCallBack,server);
31         }
32         static void AcceptCallBack(IAsyncResult ar)
33         {
34             Socket server=ar.AsyncState as Socket;
35             Socket clientSocket=server.EndAccept(ar);
36 
37             string msg = "恭喜你连接成功";
38             byte[] data = Encoding.UTF8.GetBytes(msg);
39             clientSocket.Send(data);
40 
41             //异步接收
42             dataBuffer = new byte[1024];
43             clientSocket.BeginReceive(message.Data, message.StarIndex,message.RemainSize , SocketFlags.None, ReceiveCallBack, clientSocket);
44             server.BeginAccept(AcceptCallBack, server);
45         }
46         static Message message = new Message();
47         static byte[] dataBuffer = new byte[1024];
48         static void ReceiveCallBack(IAsyncResult ar)
49         {
50             //检测数据接收结束
51             Socket clientSocket=null;
52             try
53             {
54                 clientSocket = ar.AsyncState as Socket;
55                 int count = clientSocket.EndReceive(ar);
56                 if (count==0)
57                 {
58                     clientSocket.Close();
59                     return;
60                 }
61                 message.AddCount(count);
62                 message.ReadMassage();
63                 clientSocket.BeginReceive(message.Data, message.StarIndex, message.RemainSize, SocketFlags.None, ReceiveCallBack, clientSocket);
64             }
65             catch (Exception e)
66             {
67                 clientSocket.Close();
68                 Console.WriteLine(e.Message);
69             }
70 
71             //重复接收
72         }
73     }
74 }
Program
 1 using System;
 2 using System.Net;
 3 using System.Net.Sockets;
 4 using System.Text;
 5 
 6 namespace 客户端1
 7 {
 8     class Program
 9     {
10         static void Main(string[] args)
11         {
12             Socket clientSokcet = new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
13 
14             clientSokcet.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"),1234));
15 
16             byte[] data = new byte[1024];
17             int count = clientSokcet.Receive(data);
18             string msg = Encoding.UTF8.GetString(data, 0, count);
19             System.Console.WriteLine(msg);
20 
21             //while (true)
22             //{
23             //    string s = Console.ReadLine();
24             //    if (s == "a")
25             //    {
26             //        clientSokcet.Close();
27             //        return;
28             //    }
29             //    clientSokcet.Send(Encoding.UTF8.GetBytes(s));
30             //}
31             for (int i = 0; i < 100; i++)
32             {
33                 clientSokcet.Send(Message.GetByte(i.ToString()));
34             }
35             //数据的粘包
36 
37 
38             Console.ReadKey();
39         }
40     }
41 }
客户端
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 namespace 客户端1
 8 {
 9     class Message
10     {
11         public static byte[] GetByte(string data)
12         {
13             byte[] dataByte= Encoding.UTF8.GetBytes(data);//数据
14             int dataLength= dataByte.Length;
15             byte[] lengthBytes= BitConverter.GetBytes(dataLength);
16 
17             byte[] newByte=lengthBytes.Concat(dataByte).ToArray();
18 
19             return newByte;
20         }
21     }
22 }
客户端的信息

 

一。这个是服务器

创建一个socket 地址,传输方式(流的方式),协议类型

本地ip地址的写法:

绑定ip地址和端口号:


监听:多少秒钟监听一次
持续监听:

 

 客户端的socket:

 

 给客户端发送消息:

 

 总的客户端发送消息:

 

 

 服务器接受:

 异步接受的方式
//字节类型,从头开始存,代表接收的长度,枚举类型的(接收和发送数据的行为),需要一个回调函数(一个方法),回调函数 的参数(把服务器给他传入)

 

回调方法接收的时候必须是这个类型的值

 

 转换数据类型

 

 

所有接收到数据的长度:

 

 存起来:

 

 每次接收完 再调用自己:

———————————————————————————————————————————

 二。这个号是客户端

 

 创建。链接:

接收:

 

穿消息给服务器断筋:

 

服务器可以重复接收客户端消息:

 

 

如何实现多个客户端链接服务器?

 

不用这个同步接收的方式,

改用异步接收:

还需要一个异步接收客户端消息方法:

 

 

 

 在方法里拿到服务器:

调用服务器里的结束,接收到的就是客户端:

 

 

 

同步接收消息

 

 

客户端发送消息的重复接收 链接的重负:

 

 接收消息是只有一个

 

 有时候对的:

 

 客户端关闭服务器错误的问题?

改正方式:

 

 

 

客户端非正常的关闭???
如果你输入的值等于某个数字的时候,关闭.

这样的话一直死循环:

也即是它一直还在这个地方,才一直循环

改正方法,如果接收的数据字节只有0个:

 

 

 

---恢复内容结束---

---恢复内容开始---

 

一。这个是服务器

创建一个socket 地址,传输方式(流的方式),协议类型

本地ip地址的写法:

绑定ip地址和端口号:


监听:多少秒钟监听一次
持续监听:

 

 客户端的socket:

 

 给客户端发送消息:

 

 总的客户端发送消息:

 

 

 服务器接受:

 异步接受的方式
//字节类型,从头开始存,代表接收的长度,枚举类型的(接收和发送数据的行为),需要一个回调函数(一个方法),回调函数 的参数(把服务器给他传入)

 

回调方法接收的时候必须是这个类型的值

 

 转换数据类型

 

 

所有接收到数据的长度:

 

 存起来:

 

 每次接收完 再调用自己:

———————————————————————————————————————————

 二。这个号是客户端

 

 创建。链接:

接收:

 

穿消息给服务器断筋:

 

服务器可以重复接收客户端消息:

 

 

如何实现多个客户端链接服务器?

 

不用这个同步接收的方式,

改用异步接收:

还需要一个异步接收客户端消息方法:

 

 

 

 在方法里拿到服务器:

调用服务器里的结束,接收到的就是客户端:

 

 

 

同步接收消息

 

 

客户端发送消息的重复接收 链接的重负:

 

 接收消息是只有一个

 

 有时候对的:

 

 客户端关闭服务器错误的问题?

改正方式:

 

 

 

客户端非正常的关闭???
如果你输入的值等于某个数字的时候,关闭.

这样的话一直死循环:

也即是它一直还在这个地方,才一直循环

改正方法,如果接收的数据字节只有0个:

 

 

应该是接收一百次,可是一次就接收完了

 这种只有TCp有的特征,发现你发的这个是小数据 就一次性了,就叫数据的粘包

 要解决这个问题:

发消息的时候,不发字节 发数组,把长度和数据一起放包里发送


 添加一个新类 专门处理这个消息:

把消息传进来,
先转换数据
再去获得他的长度,

把长度也转换为字节:

 

整数类型永远占用4个字节 

 再来一个数组把 数据长度 数组长度结合起来,(数组长度在前 数据在后)

 

 到客户端的时候就不直接发送tostring了,而是

 

服务器解析消息的时候也的改变

 服务器也添加新类:

 先解析前四个字节 再往后 然后
添加一个数组 接收一下:

一个新的方法,去解析粘包的数据,一直解析,直到发现接收的数组小于4,就不解析了
没有数据不解析了

 

转换数据类型为int类型,

从4的位置开始解析,

第一条信息就解析出来了

 

 把解析出来的第一条数据砍掉,放到一个新的数组里面去,
从数据的长度,加上四的长度:
复制剩余的长度=总长-4-第一条长

 

 添加属性:

剩余的长度的方法:
剩余长度=总长度-用过的长度:

每次得新的长度 ,加起来:

 

类写完 到服务器里更新

 不能用以前的解析了,

 

 存如这个数组里面

 

从哪里开始从 从已经存的长度开始存,
能存多长(还能存类的方法)

 

解析也饿的换:
首先更新message里面的数据,

再用法法

 

 

 

上边就是完整的了
  最难的就是这里了

 

---恢复内容结束---

posted @ 2018-11-23 11:33  白纸菇凉  阅读(251)  评论(0编辑  收藏  举报