• C# .NET Socket 简单实用框架,socket组件封装


    参考资料 https://www.cnblogs.com/coldairarrow/p/7501645.html

    根据.NET Socket 简单实用框架进行了改造,这个代码对socket通信封装还是不错的。简单,逻辑清晰,资料中的代码唯一问题发送信息很频繁,会导致接收信息发生问题。改造后的代码如下

    服务端源文件:

    SocketServer.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Face.SocketServer
    {
        /// <summary>
        /// Socket服务端
        /// </summary>
        public class SocketServer
        {
    
    
            #region 内部成员
    
            private Socket _socket = null;
    
            private bool _isListen = true;
            public static ManualResetEvent allDone = new ManualResetEvent(false);
            private void StartListen()
            {
    
                try
                {
                    _socket.BeginAccept(asyncResult =>
                    {
                        try
                        {
                            Socket newSocket = _socket.EndAccept(asyncResult);
    
                            //马上进行下一轮监听,增加吞吐量
                            if (_isListen)
                                StartListen();
    
                            SocketConnection newClient = new SocketConnection(newSocket, this)
                            {
                                HandleRecMsg = HandleRecMsg == null ? null : new Action<string, SocketConnection, SocketServer>(HandleRecMsg),
                                HandleClientClose = HandleClientClose == null ? null : new Action<SocketConnection, SocketServer>(HandleClientClose),
                                HandleSendMsg = HandleSendMsg == null ? null : new Action<byte[], SocketConnection, SocketServer>(HandleSendMsg),
                                HandleException = HandleException == null ? null : new Action<Exception>(HandleException),
                                HandleSendException= HandleSendException == null ? null : new Action<Exception>(HandleSendException)
                            };
    
                            newClient.StartRecMsg();
                            ClientList.AddLast(newClient);
    
                            HandleNewClientConnected?.Invoke(this, newClient);
                        }
                        catch (Exception ex)
                        {
                            HandleException?.Invoke(ex);
                        }
                    }, null);
                }
                catch (Exception ex)
                {
                    HandleException?.Invoke(ex);
                }
            }
          
      
            #endregion
    
            #region 外部接口
    
            /// <summary>
            /// 开始服务,监听客户端
            /// </summary>
            public void StartServer()
            {
                try
                {
                    //实例化套接字(ip4寻址协议,流式传输,TCP协议)
                    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    //创建ip对象
                    IPAddress address = IPAddress.Parse(ApplicationConfig.Ins.SocketIP);
                    //创建网络节点对象包含ip和port
                    IPEndPoint endpoint = new IPEndPoint(address, ApplicationConfig.Ins.SocketPort);
                    //将 监听套接字绑定到 对应的IP和端口
                    _socket.Bind(endpoint);
                    //设置监听队列长度为Int32最大值(同时能够处理连接请求数量)
                    _socket.Listen(int.MaxValue);
                    //开始监听客户端
                    StartListen();
                    HandleServerStarted?.Invoke(this);
                }
                catch (Exception ex)
                {
                    StartException?.Invoke(ex);
                }
            }
    
            /// <summary>
            /// 所有连接的客户端列表
            /// </summary>
            public LinkedList<SocketConnection> ClientList { get; set; } = new LinkedList<SocketConnection>();
    
            /// <summary>
            /// 关闭指定客户端连接
            /// </summary>
            /// <param name="theClient">指定的客户端连接</param>
            public void CloseClient(SocketConnection theClient)
            {
                theClient.Close();
            }
    
            #endregion
    
            #region 公共事件
    
            /// <summary>
            /// 异常处理程序
            /// </summary>
            public Action<Exception> HandleException { get; set; }
    
            /// <summary>
            /// 发送消息异常处理程序
            /// </summary>
            public Action<Exception> HandleSendException { get; set; }
            
            /// <summary>
            /// 启动异常程序
            /// </summary>
            public Action<Exception> StartException { get; set; }
    
            #endregion
    
            #region 服务端事件
    
            /// <summary>
            /// 服务启动后执行
            /// </summary>
            public Action<SocketServer> HandleServerStarted { get; set; }
    
            /// <summary>
            /// 当新客户端连接后执行
            /// </summary>
            public Action<SocketServer, SocketConnection> HandleNewClientConnected { get; set; }
    
            /// <summary>
            /// 服务端关闭客户端后执行
            /// </summary>
            public Action<SocketServer, SocketConnection> HandleCloseClient { get; set; }
    
            #endregion
    
            #region 客户端连接事件
    
            /// <summary>
            /// 客户端连接接受新的消息后调用
            /// </summary>
            public Action<string, SocketConnection, SocketServer> HandleRecMsg { get; set; }
    
            /// <summary>
            /// 客户端连接发送消息后回调
            /// </summary>
            public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }
    
            /// <summary>
            /// 客户端连接关闭后回调
            /// </summary>
            public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }
    
    
    
            #endregion
        }
    }
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Face.SocketServer
    {
        /// <summary>
        /// Socket连接,双向通信
        /// </summary>
        public class SocketConnection
        {
            #region 构造函数
    
            public SocketConnection(Socket socket, SocketServer server)
            {
                _socket = socket;
                _server = server;
            }
    
            #endregion
    
            #region 私有成员
    
            private readonly Socket _socket;
            private bool _isRec = true;
            private SocketServer _server = null;
            private bool IsSocketConnected()
            {
                bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
                bool part2 = (_socket.Available == 0);
                if (part1 && part2)
                    return false;
                else
                    return true;
            }
    
    
    
            #endregion
    
    
    
            #region 外部接口
    
            /// <summary>
            /// 开始接受客户端消息
            /// </summary>
            public void StartRecMsg()
            {
    
                try
                {
                    byte[] container = new byte[1024 * 1024 * 6];
                    _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
                    {
                        try
                        {
                            int length = _socket.EndReceive(asyncResult);
                            ///asyncResult.AsyncWaitHandle.Close();
                            //马上进行下一轮接受,增加吞吐量
                            if (length > 0 && _isRec && IsSocketConnected())
                                StartRecMsg();
    
                            if (length > 0)
                            {
                                byte[] recBytes = new byte[length];
                                Array.Copy(container, 0, recBytes, 0, length);
                                string msgJson = Encoding.UTF8.GetString(recBytes);
                                if (msgJson.Contains("¤€") && msgJson.Contains("€¤"))
                                {
                                    string[] arrymsg = msgJson.Replace("¤€", "").Split('');
                                    foreach (string msgitem in arrymsg)
                                    {
                                        if (string.IsNullOrEmpty(msgitem))
                                            continue;
                                        if (msgitem.Substring(msgitem.Length - 2, 2) == "€¤")
                                        {
                                            string msgitemjson = msgitem.Substring(0, msgitem.Length - 2);
                                            //处理消息
                                            HandleRecMsg?.Invoke(msgitemjson, this, _server);
                                        }
                                    }
                                }
                                else {
                                    HandleException?.Invoke(new Exception($"接收到错误指令,具体指令为:{msgJson}"));
                                }
                            }
                            else
                                Close();
                        }
                        catch (Exception ex)
                        {
                            HandleException?.Invoke(ex);
                            Close();
                        }
                    }, null);
                }
                catch (Exception ex)
                {
                    HandleException?.Invoke(ex);
                    Close();
                }
            }
    
            /// <summary>
            /// 发送数据
            /// </summary>
            /// <param name="bytes">数据字节</param>
            private void Send(byte[] bytes)
            {
                try
                {
                   
                    _socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
                    {
                        try
                        {
                            int length = _socket.EndSend(asyncResult);
                            HandleSendMsg?.Invoke(bytes, this, _server);
                        }
                        catch (Exception ex)
                        {
                            HandleSendException?.Invoke(ex);
                        }
                    }, null);
                }
                catch (Exception ex)
                {
                    HandleSendException?.Invoke(ex);
                }
            }
    
            /// <summary>
            /// 发送字符串(默认使用UTF-8编码)
            /// </summary>
            /// <param name="msgStr">字符串</param>
            public void Send(string msgStr)
            {
                Send(Encoding.UTF8.GetBytes("¤€" + msgStr + "€¤"));
            }
    
            /// <summary>
            /// 发送字符串(使用自定义编码)
            /// </summary>
            /// <param name="msgStr">字符串消息</param>
            /// <param name="encoding">使用的编码</param>
            public void Send(string msgStr, Encoding encoding)
            {
                Send(encoding.GetBytes("¤€" + msgStr + "€¤"));
            }
    
            /// <summary>
            /// 传入自定义属性
            /// </summary>
            public object Property { get; set; }
    
            /// <summary>
            /// 关闭当前连接
            /// </summary>
            public void Close()
            {
                try
                {
                    _isRec = false;
                    _socket.Disconnect(false);
                    _server.ClientList.Remove(this);
                    HandleClientClose?.Invoke(this, _server);
                    _socket.Close();
                    _socket.Dispose();
                    GC.Collect();
                }
                catch (Exception ex)
                {
                    HandleException?.Invoke(ex);
                }
            }
    
            #endregion
    
            #region 事件处理
    
            /// <summary>
            /// 客户端连接接受新的消息后调用
            /// </summary>
            public Action<string, SocketConnection, SocketServer> HandleRecMsg { get; set; }
    
            /// <summary>
            /// 客户端连接发送消息后回调
            /// </summary>
            public Action<byte[], SocketConnection, SocketServer> HandleSendMsg { get; set; }
    
            /// <summary>
            /// 客户端连接关闭后回调
            /// </summary>
            public Action<SocketConnection, SocketServer> HandleClientClose { get; set; }
    
            /// <summary>
            /// 异常处理程序
            /// </summary>
            public Action<Exception> HandleException { get; set; }
    
    
            /// <summary>
            /// 发送消息到客户端异常
            /// </summary>
            public Action<Exception> HandleSendException { get; set; }
    
    
            #endregion
        }
    }

    上面放上的是框架代码,接下来介绍下如何使用

    首先,服务端使用方式:

     //创建服务器对象,默认监听本机0.0.0.0,端口12345
                SocketServer server = new SocketServer();
                faceLogic = new FaceLogic();
                //处理从客户端收到的消息
                server.HandleRecMsg = new Action<string, SocketConnection, SocketServer>((msg, client, theServer) =>
                {
                    //Log($"调用次数", true);
                    lock (obj)
                    {
                        paramList.Add(new ParamEntity() { ParamFace = msg, socketClient = client });
                        if (IsRun == false)
                        {
                            IsRun = true;
                            HandleMsg();
                        }
                    }
                });
    
                //处理服务器启动后事件
                server.HandleServerStarted = new Action<SocketServer>(theServer =>
                {
                    Log("服务已启动************", true);
                });
    
                //处理新的客户端连接后的事件
                server.HandleNewClientConnected = new Action<SocketServer, SocketConnection>((theServer, theCon) =>
                {
                    Log($@"一个新的客户端接入,当前连接数:{theServer.ClientList.Count}", true);
                });
    
                //处理客户端连接关闭后的事件
                server.HandleClientClose = new Action<SocketConnection, SocketServer>((theCon, theServer) =>
                {
                    Log($@"一个客户端关闭,当前连接数为:{theServer.ClientList.Count}", true);
                });
                //处理异常
                server.HandleException = new Action<Exception>(ex =>
                {
                    Log("Socket处理异常:" + ex.Message, true);
                    Logs.Instance.Error("Socket处理异常:" + ex.Message);
                });
                //处理异常
                server.HandleSendException = new Action<Exception>(ex =>
                {
                    Log("Socket发送消息处理异常:" + ex.Message, true);
                    Logs.Instance.Error("Socket发送消息处理异常:" + ex.Message);
                });
                ///启动异常
                server.StartException = new Action<Exception>(ex =>
                {
                    Log("Socket服务启动失败:" + ex.Message, true);
                    Logs.Instance.Error("Socket服务启动失败:" + ex.Message);
                });
                //服务器启动
                server.StartServer();
                Log("启动Socket通信服务端完成。");

    客户端使用方式:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Net.Sockets;
    using System.Text;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace Face.SocketClient
    {
        /// <summary>
        /// Socket客户端
        /// </summary>
        public class SocketClient
        {
    
    
            #region 内部成员
    
            private Socket _socket = null;
    
            private bool _isRec = true;
            private bool _IsRun = false;
            public bool IsRun { get { return _IsRun; } }
            private bool IsSocketConnected()
            {
                bool part1 = _socket.Poll(1000, SelectMode.SelectRead);
                bool part2 = (_socket.Available == 0);
                if (part1 && part2)
                    return false;
                else
                    return true;
            }
           
            /// <summary>
            /// 开始接受客户端消息
            /// </summary>
            public void StartRecMsg()
            {
                try
                {
                    byte[] container = new byte[1024 * 1024 * 2];
                    _socket.BeginReceive(container, 0, container.Length, SocketFlags.None, asyncResult =>
                    {
                        try
                        {
                            int length = _socket.EndReceive(asyncResult);
    
                            //马上进行下一轮接受,增加吞吐量
                            if (length > 0 && _isRec && IsSocketConnected())
                                StartRecMsg();
    
                            if (length > 0)
                            {
                                byte[] recBytes = new byte[length];
                                Array.Copy(container, 0, recBytes, 0, length);
    
                                string msgJson = Encoding.UTF8.GetString(recBytes);
                                if (msgJson.Contains("¤€") && msgJson.Contains("€¤"))
                                {
                                    string[] arrymsg = msgJson.Replace("¤€", "").Split('');
                                    foreach (string msgitem in arrymsg)
                                    {
                                        if (string.IsNullOrEmpty(msgitem))
                                            continue;
                                        if (msgitem.Substring(msgitem.Length - 2, 2) == "€¤")
                                        {
                                            string msgitemjson = msgitem.Substring(0, msgitem.Length - 2);
                                            //处理消息
                                            HandleRecMsg?.Invoke(msgitemjson, this);
                                        }
                                    }
                                }
                                else
                                {
                                    HandleException?.Invoke(new Exception($"接收到错误指令,具体指令为:{msgJson}"));
                                }
                            }
                            else
                                Close();
                        }
                        catch (Exception ex)
                        {
                            if (ex.Message.Contains("远程主机强迫关闭")) {
                                _IsRun = false;
                            }
                            HandleException?.Invoke(ex);
                            Close();
                        }
                    }, null);
                }
                catch (Exception ex)
                {
                    if (ex.Message.Contains("远程主机强迫关闭"))
                    {
                        _IsRun = false;
                    }
                    HandleException?.Invoke(ex);
                    Close();
                }
            }
    
            #endregion
    
            #region 外部接口
    
            /// <summary>
            /// 开始服务,连接服务端
            /// </summary>
            public void StartClient()
            {
                try
                {
                    //实例化 套接字 (ip4寻址协议,流式传输,TCP协议)
                    _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                    //创建 ip对象
                    IPAddress address = IPAddress.Parse(ApplicationConfig.Ins.ServerIP);
                    //创建网络节点对象 包含 ip和port
                    IPEndPoint endpoint = new IPEndPoint(address, ApplicationConfig.Ins.ServerPort);
                  
                    //将 监听套接字  绑定到 对应的IP和端口
                    _socket.BeginConnect(endpoint, asyncResult =>
                    {
                        try
                        {
                            _socket.EndConnect(asyncResult);
                            //开始接受服务器消息
                            StartRecMsg();
                            _IsRun = true;
                            HandleClientStarted?.Invoke(this);
                           
                        }
                        catch (Exception ex)
                        {
                               _IsRun = false;
                               StartException?.Invoke(ex);
                        }
                    }, null);
                }
                catch (Exception ex)
                {
                    _IsRun = false;
                    StartException?.Invoke(ex);
                }
            }
    
            /// <summary>
            /// 发送数据
            /// </summary>
            /// <param name="bytes">数据字节</param>
            private void Send(byte[] bytes)
            {
                try
                {
                    //Thread.Sleep(250);
                    _socket.BeginSend(bytes, 0, bytes.Length, SocketFlags.None, asyncResult =>
                        {
                            try
                            {
                                int length = _socket.EndSend(asyncResult);
                                HandleSendMsg?.Invoke(bytes, this);
    
                            }
                            catch (Exception ex)
                            {
                                HandleException?.Invoke(ex);
                            }
    
                        }, null);
                }
                catch (Exception ex)
                {
                    HandleException?.Invoke(ex);
                }
            }
    
            /// <summary>
            /// 发送字符串(默认使用UTF-8编码)
            /// </summary>
            /// <param name="msgStr">字符串</param>
            public void Send(string msgStr)
            {
    
                Send(Encoding.UTF8.GetBytes("¤€" + msgStr+ "€¤"));
            }
    
            /// <summary>
            /// 发送字符串(使用自定义编码)
            /// </summary>
            /// <param name="msgStr">字符串消息</param>
            /// <param name="encoding">使用的编码</param>
            public void Send(string msgStr, Encoding encoding)
            {
    
                Send(encoding.GetBytes("¤€" + msgStr + "€¤"));
            }
    
            /// <summary>
            /// 传入自定义属性
            /// </summary>
            public object Property { get; set; }
    
            /// <summary>
            /// 关闭与服务器的连接
            /// </summary>
            public void Close()
            {
                try
                {
                    _isRec = false;
                    _socket.Disconnect(false);
                    HandleClientClose?.Invoke(this);
                }
                catch (Exception ex)
                {
                    HandleException?.Invoke(ex);
                }
            }
    
            #endregion
    
            #region 事件处理
    
            /// <summary>
            /// 客户端连接建立后回调
            /// </summary>
            public Action<SocketClient> HandleClientStarted { get; set; }
    
            /// <summary>
            /// 处理接受消息的委托
            /// </summary>
            public Action<string, SocketClient> HandleRecMsg { get; set; }
    
            /// <summary>
            /// 客户端连接发送消息后回调
            /// </summary>
            public Action<byte[], SocketClient> HandleSendMsg { get; set; }
    
            /// <summary>
            /// 客户端连接关闭后回调
            /// </summary>
            public Action<SocketClient> HandleClientClose { get; set; }
    
    
            /// <summary>
            /// 启动时报错误
            /// </summary>
            public Action<Exception> StartException { get; set; }
            /// <summary>
            /// 异常处理程序
            /// </summary>
            public Action<Exception> HandleException { get; set; }
    
            #endregion
        }
    
    }
  • 相关阅读:
    HDU 2955 Robberies(01背包)
    HDU 2602 Bone Collector(01背包)
    HUST 1352 Repetitions of Substrings(字符串)
    HUST 1358 Uiwurerirexb jeqvad(模拟解密)
    HUST 1404 Hamming Distance(字符串)
    HDU 4520 小Q系列故事――最佳裁判(STL)
    HDU 2058 The sum problem(枚举)
    【破解】修改程序版权、添加弹窗
    HDU 1407 测试你是否和LTC水平一样高(枚举)
    HDU 1050 Moving Tables(贪心)
  • 原文地址:https://www.cnblogs.com/PlatformSolution/p/11887254.html
Copyright © 2020-2023  润新知