风轻云淡

-------生活没有抱怨,只有自己的不努力,当才华撑不起梦想与野心,不断学习是你唯一的选择。没有伞的孩子必须努力奔跑...

导航

C# Socket 处理 拆包、粘包

1、采用TCP自定义协议通讯,协议由02(byte) + json字符串(byte[]) +03(byte)组成。

------Socket_Client.cs 服务端
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace MyTcp
{
    public class Socket_Client
    {
        //接收绑定事件
        public delegate void ReceiveDelegate(string json);
        public event ReceiveDelegate onReceiveHandler;
        //----------------------------------------------
        private Socket ClientSocket;
        private string _serverip = "";
        private int _port = 0;
        //----------------------------------------------
        public bool KeepAlive = true;
        public Socket_Client(string ServerIp, int Port)
        {
            _serverip = ServerIp;
            _port = Port;
        }
        private void KeepAliveCheck()
        {
            while(true)
            {
                try
                {
                    Console.WriteLine("keep alive");
                    if (ClientSocket != null)
                    {
                        ClientSocket.Send(new byte[] { });//发送空字符
                    }
                    Thread.Sleep(5000);
                   // Thread.Sleep(600000);//10分钟
                }catch(Exception ex)
                {
                    MyLog.Log.v(ex);
                    break;
                }
            }
        }
        public void Connect()
        {
            try
            {
                IPAddress ipAddr = IPAddress.Parse(_serverip);
                IPEndPoint endPoint = new IPEndPoint(ipAddr, _port);
                ClientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                ClientSocket.Connect(endPoint);  //与远程主机建立连接
                Console.WriteLine("成功连接到{0}。", ClientSocket.RemoteEndPoint);

                Thread recTh = new Thread(RecMsg);
                recTh.IsBackground = true;
                recTh.Start(ClientSocket);
                //启动线程每隔10分钟检查连通性
                Thread threadCheck = new Thread(KeepAliveCheck);
                threadCheck.IsBackground = true;
                threadCheck.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine("连接失败:" + ex.Message);
                MyLog.Log.v(ex);
            }
        }
        private void RecMsg(object o)
        {
            Socket connSocket = o as Socket;
            while (true)
            {
                try
                {
                    List<byte> lstArr = new List<byte>();
                    byte[] buffer = new Byte[1024];
                    int len = 0;
                    while ((len = connSocket.Receive(buffer)) > 0)
                    {
                        for (int i = 0; i < len; i++)
                        {
                            lstArr.Add(buffer[i]);
                        }
                        //处理粘包/拆包数据
                        lstArr = getRemaining(lstArr);
                    }
                }
                catch (Exception ex)
                { //异常终止接收数据
                    MyLog.Log.v(ex);
                    throw ex;//抛出异常并退出线程
                }
            }
        }
        private List<byte> getRemaining(List<byte> lstArr)
        {
            if (lstArr.Count == 0)
                return lstArr;
            List<byte> newbyte = new List<byte>();
            int _lasindex = 0;
            for (int i = 0; i < lstArr.Count; i++)
            {
                if (lstArr[i] == 3 && i > 0 && lstArr[i - 1] == 125)
                {////结束字符 ascii码 "}"对应125
                    _lasindex = i;
                    break;
                }
            }
            if (_lasindex == 0)
                return lstArr;
            string _str = "";
            //截取字符串
            for (int i = 0; i < lstArr.Count; i++)
            {
                if (lstArr[i] == 2 && lstArr.Count > (i + 1) && lstArr[i + 1] == 123)
                {//ascii码 "{"对应123
                    //  _str = System.Text.Encoding.UTF8.GetString(lstArr.GetRange(i, _lasindex - i + 1).ToArray());
                    _str = System.Text.Encoding.UTF8.GetString(lstArr.GetRange(i + 1, _lasindex - i - 1).ToArray());  //去掉02 和03
                    break;
                }
            }
            if ((lstArr.Count - _lasindex - 1) > 0)
            {
                newbyte.AddRange(lstArr.GetRange(_lasindex + 1, lstArr.Count - _lasindex - 1));
            }
            //处理数据
          //  Console.WriteLine(_str);
            if (onReceiveHandler != null)
            {
                onReceiveHandler(_str);
            }
            ////////////
            return getRemaining(newbyte);
        }
        /// <summary>
        /// 发送消息
        /// </summary>
        /// <param name="mess"></param>
        public void Send(string json)
        {
            try
            {
                Thread sendTh = new Thread(SendMsg);
                SendObj send = new SendObj();
                send.socket = ClientSocket;
                send.json = json;
                sendTh.IsBackground = true;
                sendTh.Start(send);
            }catch(Exception ex)
            {
                MyLog.Log.v(ex);
            }
        }
        public void Close()
        {
            try
            {
                if (ClientSocket != null)
                {
                    ClientSocket.Close();
                }
            }
            catch (Exception ex)
            {
                MyLog.Log.v(ex);
                throw ex;
            }
        }
        /********************************************************************/
        /// <summary>
        ///
        /// </summary>
        /// <param name="ob"></param>
        private void SendMsg(object ob)
        {
            try
            {
                SendObj sendOb = ob as SendObj;
                if (sendOb != null)
                {
                    byte[] buffer = GetWrappedTextArray(sendOb.json);
                    Console.WriteLine(System.Text.Encoding.UTF8.GetString(buffer));
                    sendOb.socket.Send(buffer, buffer.Length, SocketFlags.None);
                }
            }catch(Exception ex)
            {
                MyLog.Log.v(ex);
            }
        }
        /// <summary>
        /// 0x02{}0x03
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private byte[] GetWrappedTextArray(string text)
        {
            byte[] oldbytes = Encoding.UTF8.GetBytes(text);
            byte[] newbytes = new byte[oldbytes.Length + 2];
            newbytes[0] = 2;
            oldbytes.CopyTo(newbytes, 1);
            newbytes[newbytes.Length - 1] = 3;
            return newbytes;
        }  
        private class SendObj
        {
           public Socket socket;
           public string json;
        }
    }
}

---------Socket_Server.cs 客户端


using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace MyTcp
{
    public class Socket_Server
    { //接收绑定事件
        public delegate void ReceiveDelegate(string json);
        public event ReceiveDelegate onReceiveHandler;
        private Socket socketSrv;
        private string _serverip = "";
        private int _port = 0;
        static Dictionary<string, Socket> clientConnectionItems = new Dictionary<string, Socket> { };
        public Socket_Server(string ServerIp, int Port)
        {
            _serverip = ServerIp;
            _port = Port;
        }
        public void StartListen()
        {
            IPAddress ip = IPAddress.Parse(_serverip);
            IPEndPoint ipe = new IPEndPoint(ip, _port);
            socketSrv = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            try
            {
                socketSrv.Bind(ipe);
                socketSrv.Listen(10);
                Console.WriteLine("等待连接……");
                Thread mainTrd = new Thread(RunAccept);
                mainTrd.IsBackground = true;
                mainTrd.Start(socketSrv);
            }
            catch (Exception ex)
            {
                MyLog.Log.v(ex);
                Console.WriteLine(ex);
            }
        }
        private void RunAccept(object o)
        {
            Socket socket = o as Socket;
            while (true)
            {
                try
                {
                    Socket connection = socket.Accept();                     
                    string remoteEndPoint = connection.RemoteEndPoint.ToString();
                    Console.WriteLine("成功与" + remoteEndPoint + "客户端建立连接!\t\n");
                    clientConnectionItems.Add(remoteEndPoint, connection);
                    Thread thread = new Thread(new ParameterizedThreadStart(recv));
                    thread.IsBackground = true;
                    thread.Start(connection);
                }
                catch (Exception ex)
                {
                    MyLog.Log.v(ex);
                    Console.WriteLine(ex);
                    throw;
                }
            }
        }
        /// <summary>
        /// 接收客户端发来的信息,客户端套接字对象
        /// </summary>
        /// <param name="socketclientpara"></param>    
        private void recv(object socketclientpara)
        {
            Socket socketServer = socketclientpara as Socket;
            int _FNW = 0;
            while (true)
            {
                try
                {
                    List<byte> lstArr = new List<byte>();
                    byte[] buffer = new Byte[1024];
                    int len = 0;
                    while ((len = socketServer.Receive(buffer)) > 0)
                    {
                        if (_FNW > 0)
                            _FNW = 0;
                        for (int i = 0; i < len; i++)
                        {
                            lstArr.Add(buffer[i]);
                        }
                        //处理粘包/拆包数据
                        lstArr = getRemaining(lstArr);
                    }
                    if(len==0)
                    {
                        _FNW++;
                        Thread.Sleep(5000);//15秒后断开连接
                        if (_FNW > 3)
                        {
                            //异常终止接收数据
                            MyLog.Log.v(socketServer.RemoteEndPoint + "远程连接关闭");
                            clientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
                            Console.WriteLine("Client Count:" + clientConnectionItems.Count);
                            //提示套接字监听异常  
                            Console.WriteLine("客户端" + socketServer.RemoteEndPoint + "已经中断连接");
                            socketServer.Close();
                            socketServer.Dispose();
                            break;
                        }
                    }
                }
                catch (Exception ex)
                {
                    //异常终止接收数据
                    MyLog.Log.v(ex);
                    clientConnectionItems.Remove(socketServer.RemoteEndPoint.ToString());
                    Console.WriteLine("Client Count:" + clientConnectionItems.Count);
                    //提示套接字监听异常  
                    Console.WriteLine("客户端" + socketServer.RemoteEndPoint + "已经中断连接" + "\r\n" + ex.Message + "\r\n" + ex.StackTrace + "\r\n");
                    socketServer.Close();
                    socketServer.Dispose();
                    break;
                }
            }
        }

        private List<byte> getRemaining(List<byte> lstArr)
        {
            if (lstArr.Count == 0)
                return lstArr;
            List<byte> newbyte = new List<byte>();
            int _lasindex = 0;
            for (int i = 0; i < lstArr.Count; i++)
            {
                if (lstArr[i] == 3 && i > 0 && lstArr[i - 1] == 125)
                {////结束字符 //125      0x7D      }
                    _lasindex = i;
                    break;
                }
            }
            if (_lasindex == 0)
                return lstArr;
            string _str = "";
            //截取字符串
            for (int i = 0; i < lstArr.Count; i++)
            {
                if (lstArr[i] == 2 && lstArr.Count > (i + 1) && lstArr[i + 1] == 123)
                {
                    //_str = System.Text.Encoding.UTF8.GetString(lstArr.GetRange(i, _lasindex - i + 1).ToArray());
                    _str = System.Text.Encoding.UTF8.GetString(lstArr.GetRange(i+1, _lasindex - i-1).ToArray());  //去掉02 和03
                    break;
                }
            }
            if ((lstArr.Count - _lasindex - 1) > 0)
            {
                newbyte.AddRange(lstArr.GetRange(_lasindex + 1, lstArr.Count - _lasindex - 1));
            }
            //处理数据
            //  Console.WriteLine(_str);
            if (onReceiveHandler != null)
            {
                onReceiveHandler(_str);
            }
            ////////////
            return getRemaining(newbyte);
        }
        public void Send(string json)
        {
            try
            {
                if (clientConnectionItems != null && clientConnectionItems.Count > 0)
                {
                    Thread sendTh = new Thread(SendMsg);
                    sendTh.IsBackground = true;
                    sendTh.Start(json);
                }
            }
            catch (Exception ex)
            {
                MyLog.Log.v(ex);
            }
        }

        public void Close()
        {
            try
            {
                if(clientConnectionItems!=null&& clientConnectionItems.Count>0)
                {
                    foreach (var item in clientConnectionItems)
                    {
                        try
                        {
                            item.Value.Close();
                            item.Value.Dispose();
                        }catch(Exception ex)
                        {
                            Console.WriteLine("关闭连接"+item.Key+"出错:"+ex);
                            MyLog.Log.v("关闭连接"+item.Key+"出错:"+ex.Message);
                        }
                    }
                }
                if (socketSrv != null)
                {
                    socketSrv.Close();
                    socketSrv.Dispose();
                }
            }
            catch (Exception ex)
            {
                MyLog.Log.v(ex);
                Console.WriteLine(ex);
                throw ex;
            }
        }
        /********************************************************************/
        /// <summary>
        ///
        /// </summary>
        /// <param name="ob"></param>
        private void SendMsg(object ob)
        {
            try
            {
                String _sendMess = Convert.ToString(ob) ?? "";
                byte[] buffer = GetWrappedTextArray(_sendMess);
                Console.WriteLine(System.Text.Encoding.UTF8.GetString(buffer));
                foreach (var item in clientConnectionItems)
                {
                    try
                    {   
                        item.Value.Send(buffer, buffer.Length, SocketFlags.None);
                    }
                    catch(Exception ex)
                    {
                        MyLog.Log.v(ex);
                    }
                }
            }
            catch (Exception ex)
            {
                MyLog.Log.v(ex);
            }
        }
        /// <summary>
        /// 0x02{}0x03
        /// </summary>
        /// <param name="text"></param>
        /// <returns></returns>
        private byte[] GetWrappedTextArray(string text)
        {
            byte[] oldbytes = Encoding.UTF8.GetBytes(text);
            byte[] newbytes = new byte[oldbytes.Length + 2];
            newbytes[0] = 2;
            oldbytes.CopyTo(newbytes, 1);
            newbytes[newbytes.Length - 1] = 3;
            return newbytes;
        }
    }
}
----------------------------------------------------------测试调用--------------------------------------------------------------------------

 1、启动客户端服务
    Socket_Client client = new Socket_Client("127.0.0.1", 20001);
    client.Connect();//连接
    client.onReceiveHandler += Client_onReceiveHandler;//接收消息
2、启动服务端 
    Socket_Server ss = new Socket_Server("127.0.0.1", 20001);
    ss.StartListen();//启动监听
    ss.onReceiveHandler += Ss_onReceiveHandler;//接收消息
    

 

posted on 2020-05-09 15:16  淡然→笑  阅读(1409)  评论(0编辑  收藏  举报