zoukankan      html  css  js  c++  java
  • 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
        }
    
    }
  • 相关阅读:
    文件监控(教学版)
    设备读写 之 直接方式(Direct I/O)
    过滤驱动加密文件(代码)
    Why ASMLIB and why not?
    SQL调优:Clustering Factor影响数据删除速度一例
    监控一个大事务的回滚
    crsctl status resource t init in 11.2.0.2 grid infrastructure
    Script:收集Oracle备份恢复信息
    Only ARCH Bgprocess may create archivelog?
    11g新特性:A useful View V$DIAG_INFO
  • 原文地址:https://www.cnblogs.com/PlatformSolution/p/11887254.html
Copyright © 2011-2022 走看看