不明白Socket通信原理的同学可以参考该文章:https://www.cnblogs.com/zxtceq/p/7728543.html点击打开链接
具体代码的编写参考该博客:https://www.cnblogs.com/sdyinfang/p/5519708.html点击打开链接
粘包和分包:
Socket通信时会对发送的字节数据进行分包和粘包处理,属于一种Socket内部的优化机制。
1.粘包:当发送的字节数据包比较小且频繁发送时,Socket内部会将字节数据进行粘包处理,既将频繁发送的小字节数据打包成 一个整包进行发送,降低内存的消耗。
2.分包:当发送的字节数据包比较大时,Socket内部会将发送的字节数据进行分包处理,降低内存和性能的消耗。
解决方案:将发送的字节数据的长度与字节数据拼接后发送,每次读取字节数据时先读取其长度,然后再对接收到的字节数组进行拆分和拼接处理。
具体实现代码如下:(环境:Visual Studio 2017 C#.NET控制台程序)
服务器端代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Sockets; using System.Net; using TCPClient; namespace TCPServer { class Program { static Message msg = new Message(); static void Main(string[] args) { StartServerAsync(); } /// <summary> /// 异步 /// </summary> static void StartServerAsync() { //开启服务器 Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPAddress iPAddress = IPAddress.Parse("192.168.1.108"); IPEndPoint iPEndPoint = new IPEndPoint(iPAddress, 50000); serverSocket.Bind(iPEndPoint); //绑定ip和端口号 serverSocket.Listen(0); //服务器端的监听(0代表不限个数) //Socket client = serverSocket.Accept(); //接收客户端链接,当没有接收到任何客户端链接时中断程序 //异步接收客户端链接并发送消息 serverSocket.BeginAccept(AsyncAcceptCallBack, serverSocket); Console.ReadKey(); } static void AsyncAcceptCallBack(IAsyncResult ar) { Socket serverSocket = ar.AsyncState as Socket; Socket client = serverSocket.EndAccept(ar); //向客户端发送消息 string msgStr = "努力!!奋斗!!!"; byte[] data = System.Text.Encoding.UTF8.GetBytes(msgStr); client.Send(data); //异步接收消息(回调函数) client.BeginReceive(msg.Data, msg.StartIndex, msg.Data.Length, SocketFlags.None, AsyncReceiveCallBack, client); //client.BeginReceive(msg.Data, 0, 1024, SocketFlags.None, AsyncReceiveCallBack, client); //继续等待下一个客户端连接(回调函数) serverSocket.BeginAccept(AsyncAcceptCallBack, serverSocket); } static void AsyncReceiveCallBack(IAsyncResult ar) { Socket client = null; try { client = ar.AsyncState as Socket; int count = client.EndReceive(ar); //异步时使用EndReceive接收 if (count == 0) //服务器不会接收空消息 { client.Close(); return; } msg.ReadMessage(count); //读取出第一条字节数据并删除 client.BeginReceive(msg.Data, msg.StartIndex, msg.RemainSize, SocketFlags.None, AsyncReceiveCallBack, client); } catch (Exception e) { Console.WriteLine(e); if(client != null) client.Close(); } } } }
Message类代码:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace TCPClient { class Message { private byte[] m_data = new byte[10240]; private int m_startIndex = 0; private int m_count = 0; //为一条发送的字节数据的长度 public int Count { get { return m_count; } } public byte[] Data { get { return m_data; } } public int StartIndex { get { return m_startIndex; } } public int RemainSize { get { return m_data.Length - m_count; } } /// <summary> /// 将字节数据与字节长度拼接 /// </summary> /// <param name="_msg"></param> /// <returns></returns> public static byte[] GetBytes(string _msg) { byte[] msg = System.Text.Encoding.UTF8.GetBytes(_msg); int length = msg.Length; //字节长度 byte[] newMsg = BitConverter.GetBytes(length).Concat(msg).ToArray(); //将字节长度与msg拼接 return newMsg; } /// <summary> /// 解析字节数据 /// </summary> /// <returns></returns> public void ReadMessage(int _count) { m_startIndex = 4; m_count += _count; UpdataMessage(); } /// <summary> /// 读取完成字节数据后删除第一条字节数据 /// </summary> private void UpdataMessage() { while (true) { int count = BitConverter.ToInt32(m_data, 0); Console.WriteLine(System.Text.Encoding.UTF8.GetString(m_data, m_startIndex, count)); m_count -= count + 4; Array.Copy(m_data, count + 4, m_data, 0, m_count); if (m_count < count + 4) break; } m_startIndex = m_count; } } }
客户端代码如下:
扫描二维码关注公众号,回复:
1730164 查看本文章
![](/qrcode.jpg)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Net.Sockets; using System.Net; namespace TCPClient { class Program { static void Main(string[] args) { TCPClientAsync(); Console.ReadKey(); } static void TCPClientAsync() { Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { client.Connect(new IPEndPoint(IPAddress.Parse("192.168.1.108"), 50000)); } catch (Exception e) { Console.WriteLine(e); return; } //从服务器接收消息 byte[] buffer = new byte[1024]; int size = client.Receive(buffer); string msgReceive = System.Text.Encoding.UTF8.GetString(buffer, 0, size); Console.Write(msgReceive); //向服务器发送消息 //while (true) //{ // string msg = Console.ReadLine(); // if (msg == "e") // { // client.Close(); // return; // } // Console.Write(msg); // byte[] data = GetBytes(msg); // client.Send(data); //} for (int i = 0; i < 1000; i++) { byte[] data = GetBytes(i.ToString() + "身开始登记卡"); client.Send(data); } Console.ReadKey(); client.Close(); } /// <summary> /// 将字节数据与字节长度拼接 /// </summary> /// <param name="_msg"></param> /// <returns></returns> public static byte[] GetBytes(string _msg) { byte[] msg = System.Text.Encoding.UTF8.GetBytes(_msg); int length = msg.Length; //字节长度 byte[] newMsg = BitConverter.GetBytes(length).Concat(msg).ToArray(); //将字节长度与msg拼接 return newMsg; } } }