在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
Socket封装,支持多客户端,支持大文件传输,支持多线程并发,对较大的Socket包进行分块传输。 封装所要达到的效果,是可以像下面这样使用Socket和服务端通信,调用服务端的方法,让你在使用Socket的时候,感觉不到Socket的存在,就像是调用本地方法一样,并且支持ref参数和out参数: DemoService demoService = new DemoService(); DemoService2 demoService2 = new DemoService2(); string result = demoService.Test("测试DemoService", 1); demoService.Test2("测试DemoService", 1); string result2 = demoService2.RunTest("测试DemoService2", 2); 一、数据结构: CmdType: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataStruct { /// <summary> /// cmd类型 /// </summary> public enum CmdType { /// <summary> /// 执行方法 /// </summary> RunFunction = 1, /// <summary> /// 心跳 /// </summary> Heartbeat = 2 } } SocketData: using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace DataStruct { /// <summary> /// Socket数据 /// </summary> [Serializable] public class SocketData { /// <summary> /// 命令类型 /// </summary> public CmdType cmdType { get; set; } /// <summary> /// 类名 /// </summary> public string className { get; set; } /// <summary> /// 方法名 /// </summary> public string functionName { get; set; } /// <summary> /// 方法参数 /// </summary> public object[] funParam { get; set; } } } SocketResult: using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DataStruct { /// <summary> /// Socket返回 /// </summary> [Serializable] public class SocketResult { /// <summary> /// 方法返回值 /// </summary> public object returnValue { get; set; } /// <summary> /// 方法参数 /// </summary> public object[] param { get; set; } } } FunctionUtil(根据SocketData执行服务端的方法): using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; using System.Threading.Tasks; namespace DataStruct.Utils { /// <summary> /// 执行方法 /// </summary> public class FunctionUtil { /// <summary> /// 执行方法 /// </summary> public static object RunFunction(string applicationPath, SocketData socketData) { Assembly assembly = Assembly.LoadFile(Path.Combine(applicationPath, "DataService.dll")); object classObj = assembly.CreateInstance("DataService." + socketData.className); Type type = classObj.GetType(); MethodInfo methodInfo = type.GetMethod(socketData.functionName); ParameterInfo[] parameterInfoArr = methodInfo.GetParameters(); object result = methodInfo.Invoke(classObj, socketData.funParam); SocketResult socketResult = new SocketResult(); socketResult.returnValue = result; socketResult.param = new object[socketData.funParam.Length]; object paramObj; for (int i = 0; i < parameterInfoArr.Length; i++) { paramObj = socketData.funParam[i]; if (parameterInfoArr[i].ParameterType.IsByRef || parameterInfoArr[i].IsOut) { socketResult.param[i] = paramObj; } else { socketResult.param[i] = null; } } return socketResult; } } } 二、Socket通信封装: using System; using System.Collections.Generic; using System.Configuration; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using DataStruct.Utils; namespace DataStruct { /// <summary> /// Socket封装 /// </summary> public static class SocketHelper { #region 变量 private static object _lockSend = new object(); private static Socket serverSocket; private static Socket clientSocket; private static List<Socket> clientList = new List<Socket>(); private static System.Timers.Timer heartbeatTimer; #endregion #region 启动服务 /// <summary> /// 启动服务 /// </summary> public static void StartServer() { try { int port = Convert.ToInt32(ConfigurationManager.AppSettings["ServerPort"]); IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, port); serverSocket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); serverSocket.Bind(ipEndPoint); serverSocket.Listen(10); new Thread(new ThreadStart(delegate() { while (true) { Socket m_Client; try { m_Client = serverSocket.Accept(); m_Client.SendTimeout = 20000; m_Client.ReceiveTimeout = 20000; m_Client.SendBufferSize = 10240; m_Client.ReceiveBufferSize = 10240; clientList.Add(m_Client); LogUtil.Log("监听到新的客户端,当前客户端数:" + clientList.Count); } catch { break; } DateTime lastHeartbeat = DateTime.Now; new Thread(new ThreadStart(delegate() { try { while (true) { byte[] receiveByteArr = null; try { receiveByteArr = Receive(m_Client); } catch { break; } if (receiveByteArr != null) { SocketData data = (SocketData)SerializeUtil.Deserialize(receiveByteArr); if (data.cmdType != CmdType.Heartbeat) { object obj = null; try { obj = FunctionUtil.RunFunction(System.Windows.Forms.Application.StartupPath, data); } catch (Exception ex) { LogUtil.LogError("执行方法出错:" + ex.Message + "\r\n" + ex.StackTrace); Send(m_Client, SerializeUtil.Serialize("error:执行服务端方法出错")); } Send(m_Client, SerializeUtil.Serialize(obj)); LogUtil.Log("接收客户端数据,并向客户端返回数据"); } else { lastHeartbeat = DateTime.Now; LogUtil.Log("收到心跳包,客户端连接正常"); } } else { clientList.Remove(m_Client); LogUtil.Log("客户端正常关闭,当前客户端数:" + clientList.Count); if (m_Client.Connected) m_Client.Disconnect(false); m_Client.Close(); m_Client.Dispose(); break; } } } catch (Exception ex) { LogUtil.LogError(ex.Message + "\r\n" + ex.StackTrace); try { Send(m_Client, SerializeUtil.Serialize("error:" + ex.Message)); } catch { } } })).Start(); //检测客户端 new Thread(new ThreadStart(delegate() { try { while (true) { DateTime now = DateTime.Now; if (now.Subtract(lastHeartbeat).TotalSeconds > 300) { clientList.Remove(m_Client); LogUtil.Log("客户端已失去连接,当前客户端数:" + clientList.Count); if (m_Client.Connected) m_Client.Disconnect(false); m_Client.Close(); m_Client.Dispose(); break; } Thread.Sleep(500); } } catch (Exception ex) { LogUtil.LogError("检测客户端出错:" + ex.Message + "\r\n" + ex.StackTrace); } })).Start(); } })).Start(); LogUtil.Log("服务已启动"); } catch (Exception ex) { LogUtil.LogError("启动服务出错:" + ex.Message + "\r\n" + ex.StackTrace); } } #endregion #region 停止服务 /// <summary> /// 停止服务 /// </summary> public static void StopServer() { try { foreach (Socket socket in clientList) { if (socket.Connected) socket.Disconnect(false); socket.Close(); socket.Dispose(); } clientList.Clear(); if (serverSocket != null) { if (serverSocket.Connected) serverSocket.Disconnect(false); serverSocket.Close(); serverSocket.Dispose(); } LogUtil.Log("服务已停止"); } catch (Exception ex) { LogUtil.LogError("停止服务出错:" + ex.Message + "\r\n" + ex.StackTrace); } } #endregion #region 连接服务器 /// <summary> /// 连接服务器 /// </summary> public static void ConnectServer() { try { if (clientSocket == null || !clientSocket.Connected) { if (clientSocket != null) { clientSocket.Close(); clientSocket.Dispose(); } string ip = ConfigurationManager.AppSettings["ServerIP"]; int port = Convert.ToInt32(ConfigurationManager.AppSettings["ServerPort"]); IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), port); clientSocket = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); clientSocket.SendTimeout = 20000; clientSocket.ReceiveTimeout = 20000; clientSocket.SendBufferSize = 10240; clientSocket.ReceiveBufferSize = 10240; clientSocket.Connect(ipep); LogUtil.Log("已连接服务器"); } } catch (Exception ex) { LogUtil.LogError("连接服务器失败:" + ex.Message); } } #endregion #region 断开服务器 /// <summary> /// 断开服务器 /// </summary> public static void DisconnectServer() { try { if (clientSocket != null) { if (clientSocket.Connected) clientSocket.Disconnect(false); clientSocket.Close(); clientSocket.Dispose(); } LogUtil.Log("已断开服务器"); } catch (Exception ex) { LogUtil.LogError("断开服务器失败:" + ex.Message); } } #endregion #region 心跳 public static void StartHeartbeat() { heartbeatTimer = new System.Timers.Timer(); heartbeatTimer.Interval = 5000; heartbeatTimer.Elapsed += new System.Timers.ElapsedEventHandler((obj, eea) => { try { SocketData data = new SocketData(); data.cmdType = CmdType.Heartbeat; Send(clientSocket, SerializeUtil.Serialize(data)); } catch (Exception ex) { LogUtil.LogError("向服务器发送心跳包出错:" + ex.Message); } }); heartbeatTimer.Start(); } #endregion #region 停止心跳 public static void StopHeartbeat() { heartbeatTimer.Stop(); } #endregion #region Send /// <summary> /// Send /// </summary> public static void Send(Socket socket, byte[] data) { lock (_lockSend) { byte[] lenArr = BitConverter.GetBytes(data.Length); int sendTotal = 0; while (sendTotal < lenArr.Length) { int sendOnce = socket.Send(lenArr, sendTotal, lenArr.Length - sendTotal, SocketFlags.None); sendTotal += sendOnce; Thread.Sleep(1); } Thread.Sleep(1); int block = 10240; int count = (data.Length - 1) / block + 1; for (int i = 0; i < count; i++) { int currentBlock = block; if (i == count - 1) { currentBlock = data.Length - block * i; } sendTotal = 0; while (sendTotal < currentBlock) { int sendOnce = socket.Send(data, i * block + sendTotal, currentBlock - sendTotal, SocketFlags.None); sendTotal += sendOnce; Thread.Sleep(1); } Thread.Sleep(1); } } } #endregion #region Receive /// <summary> /// Receive /// </summary> private static byte[] Receive(Socket socket) { lock (socket) { try { int block = 4; byte[] buffer = new byte[block]; int receiveCount = socket.Receive(buffer, 0, block, SocketFlags.None); if (receiveCount == 0) { return null; } else { while (receiveCount < block) { int revCount = socket.Receive(buffer, receiveCount, buffer.Length - receiveCount, SocketFlags.None); receiveCount += revCount; Thread.Sleep(1); } int dataLength = BitConverter.ToInt32(buffer, 0); block = 10240; receiveCount = 0; byte[] result = new byte[dataLength]; while (receiveCount < dataLength) { int revCount = socket.Receive(result, receiveCount, result.Length - receiveCount, SocketFlags.None); receiveCount += revCount; Thread.Sleep(1); } try { SerializeUtil.Deserialize(result); } catch (Exception ex) { LogUtil.LogError("数据检验失败!"); string aa = ex.Message; } return result; } } catch (Exception ex) { LogUtil.LogError("接收数据出错:" + ex.Message + "\r\n" + ex.StackTrace); return null; } } } #endregion #region IsZero /// <summary> /// IsZero /// </summary> private static bool IsZero(byte[] data) { bool bl = true; foreach (byte b in data) { if (b != 0) { return false; } } LogUtil.LogError("接收的字节数组内容全是0"); return bl; } #endregion #region 请求 /// <summary> /// 请求 /// </summary> public static object Request(SocketData data) { try { ConnectServer(); Send(clientSocket, SerializeUtil.Serialize(data)); byte[] receiveByteArr = null; receiveByteArr = Receive(clientSocket); if (receiveByteArr != null) { object result = SerializeUtil.Deserialize(receiveByteArr); if (result.GetType() == typeof(string) && result.ToString().IndexOf("error:") == 0) { string errMsg = result.ToString().Split(':')[1]; LogUtil.LogError(errMsg); throw new Exception(errMsg); } return result; } else { if (clientSocket.Connected) clientSocket.Disconnect(false); clientSocket.Close(); clientSocket.Dispose(); return Request(data); } } catch (Exception ex) { if (clientSocket.Connected) clientSocket.Disconnect(false); LogUtil.LogError(ex.Message); throw ex; } } #endregion #region Request 请求 /// <summary> /// 请求 /// </summary> public static object Request(string className, string methodName, object[] param) { SocketData data = new SocketData(); data.className = className; data.functionName = methodName; data.funParam = param; return Request(data); } #endregion } } 三、服务端的服务接口类: DemoService: using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using DAL; using Models; namespace DataService { /// <summary> /// socket服务 /// </summary> public class DemoService { public List<BS_NoticeType_ext> GetList(ref PagerModel pager, out string str) { NoticeTypeDal noticeTypeDal = new NoticeTypeDal(); str = "测试123"; return noticeTypeDal.GetList(ref pager); } |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论