Socket封装,支持多客户端。
封装所要达到的效果,是可以像下面这样使用Socket和服务端通信,调用服务端的方法:
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; } } }
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 obj = assembly.CreateInstance("DataService." + socketData.className); Type type = obj.GetType(); return type.GetMethod(socketData.functionName).Invoke(obj, socketData.funParam); } } }
二、服务端Socket通信:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Data; using System.Drawing; using System.IO; using System.Linq; using System.Net; using System.Net.Sockets; using System.Runtime.Serialization.Formatters.Binary; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Common.Utils; using CommonDll; using DataService; using DataStruct; using DataStruct.Utils; using Newtonsoft.Json; namespace XXPLServer { public partial class Form1 : Form { #region 变量 private Socket m_ServerSocket; private List<Socket> m_ClientList = new List<Socket>(); #endregion #region Form1构造函数 public Form1() { InitializeComponent(); } #endregion #region Form1_Load private void Form1_Load(object sender, EventArgs e) { } #endregion #region 启动服务 private void btnStartServer_Click(object sender, EventArgs e) { try { btnStartServer.Enabled = false; btnStopServer.Enabled = true; int port = Convert.ToInt32(ConfigurationManager.AppSettings["ServerPort"]); IPEndPoint ipEndPoint = new IPEndPoint(IPAddress.Any, port); m_ServerSocket = new Socket(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); m_ServerSocket.Bind(ipEndPoint); m_ServerSocket.Listen(10); new Thread(new ThreadStart(delegate() { while (true) { Socket m_Client; try { m_Client = m_ServerSocket.Accept(); m_Client.SendTimeout = 20000; m_Client.ReceiveTimeout = 20000; m_ClientList.Add(m_Client); LogUtil.Log("监听到新的客户端,当前客户端数:" + m_ClientList.Count); } catch { break; } DateTime lastHeartbeat = DateTime.Now; new Thread(new ThreadStart(delegate() { try { while (true) { byte[] inBuffer = new byte[m_Client.ReceiveBufferSize]; int receiveCount; try { receiveCount = m_Client.Receive(inBuffer, m_Client.ReceiveBufferSize, SocketFlags.None);//如果接收的消息为空 阻塞 当前循环 } catch { break; } if (receiveCount != 0) { SocketData data = (SocketData)SerializeUtil.Deserialize(inBuffer); if (data.cmdType != CmdType.Heartbeat) { object obj = FunctionUtil.RunFunction(Application.StartupPath, data); m_Client.Send(SerializeUtil.Serialize(obj)); LogUtil.Log("接收客户端数据,并向客户端返回数据"); } else { lastHeartbeat = DateTime.Now; } } else { m_ClientList.Remove(m_Client); LogUtil.Log("客户端正常关闭,当前客户端数:" + m_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); } })).Start(); //检测客户端 new Thread(new ThreadStart(delegate() { try { while (true) { DateTime now = DateTime.Now; if (now.Subtract(lastHeartbeat).TotalSeconds > 20) { m_ClientList.Remove(m_Client); LogUtil.Log("客户端已失去连接,当前客户端数:" + m_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 停止服务 private void btnStopServer_Click(object sender, EventArgs e) { btnStopServer.Enabled = false; btnStartServer.Enabled = true; foreach (Socket socket in m_ClientList) { if (socket.Connected) socket.Disconnect(false); socket.Close(); socket.Dispose(); } if (m_ServerSocket != null) { if (m_ServerSocket.Connected) m_ServerSocket.Disconnect(false); m_ServerSocket.Close(); m_ServerSocket.Dispose(); } LogUtil.Log("服务已停止"); } #endregion #region Form1_FormClosing private void Form1_FormClosing(object sender, FormClosingEventArgs e) { foreach (Socket socket in m_ClientList) { if (socket.Connected) socket.Disconnect(false); socket.Close(); socket.Dispose(); } if (m_ServerSocket != null) { if (m_ServerSocket.Connected) m_ServerSocket.Disconnect(false); m_ServerSocket.Close(); m_ServerSocket.Dispose(); } LogUtil.Log("服务已停止"); } #endregion } }
三、服务端的服务接口类:
DemoService:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; namespace DataService { /// <summary> /// socket服务 /// </summary> public class DemoService { public string Test(string str, int n) { return str + ":" + n; } public void Test2(string str, int n) { string s = str + n; } } }
DemoService2:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace DataService { public class DemoService2 { public string RunTest(string str, int n) { return str + ":" + n; } } }
三、客户端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; using CommonDll; namespace Common.Utils { /// <summary> /// 服务 /// </summary> public class ServiceUtil { public static Socket clientSocket; public static object _lock = new object(); /// <summary> /// 连接服务器 /// </summary> public static void ConnectServer() { if (clientSocket == null || !clientSocket.Connected) { if (clientSocket != null) { clientSocket.Close(); clientSocket.Dispose(); } string ip = ConfigurationManager.AppSettings["ServerIP"]; IPEndPoint ipep = new IPEndPoint(IPAddress.Parse(ip), 3001); clientSocket = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp); clientSocket.SendTimeout = 20000; clientSocket.ReceiveTimeout = 20000; clientSocket.Connect(ipep); } } /// <summary> /// 请求 /// </summary> public static object Request(SocketData data) { lock (_lock) { try { ConnectServer(); clientSocket.Send(SerializeUtil.Serialize(data)); byte[] inBuffer = new byte[clientSocket.ReceiveBufferSize]; int count = clientSocket.Receive(inBuffer, clientSocket.ReceiveBufferSize, SocketFlags.None);//如果接收的消息为空 阻塞 当前循环 if (count > 0) { return SerializeUtil.Deserialize(inBuffer); } 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; } } } /// <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 ServiceUtil.Request(data); } } }
六、客户端接口类代码:
DemoService:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DataStruct; using Common.Utils; using System.Reflection; namespace ClientService { public class DemoService { public string Test(string str, int n) { object result = ServiceUtil.Request(this.GetType().Name, MethodBase.GetCurrentMethod().Name, new object[] { str, n }); return result.ToString(); } public void Test2(string str, int n) { object result = ServiceUtil.Request(this.GetType().Name, MethodBase.GetCurrentMethod().Name, new object[] { str, n }); } } }
DemoService2:
using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using Common.Utils; using DataStruct; namespace ClientService { public class DemoService2 { public string RunTest(string str, int n) { object result = ServiceUtil.Request(this.GetType().Name, MethodBase.GetCurrentMethod().Name, new object[] { str, n }); return result.ToString(); } } }
六:客户端测试代码:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Configuration; using System.Data; using System.Drawing; using System.Linq; using System.Net; using System.Net.Sockets; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Windows.Forms; using Common.Utils; using CommonDll; using DataStruct; using ClientService; namespace XXPLClient { public partial class Form1 : Form { #region 变量 private System.Timers.Timer m_timer; #endregion #region Form1构造函数 public Form1() { InitializeComponent(); } #endregion #region Form1_Load private void Form1_Load(object sender, EventArgs e) { try { //连接服务器 ServiceUtil.ConnectServer(); } catch (Exception ex) { MessageBox.Show("连接服务器失败:" + ex.Message); } //心跳包 m_timer = new System.Timers.Timer(); m_timer.Interval = 5000; m_timer.Elapsed += new System.Timers.ElapsedEventHandler((obj, eea) => { try { lock (ServiceUtil._lock) { SocketData data = new SocketData(); data.cmdType = CmdType.Heartbeat; ServiceUtil.ConnectServer(); ServiceUtil.clientSocket.Send(SerializeUtil.Serialize(data)); } } catch (Exception ex) { LogUtil.LogError("向服务器发送心跳包出错:" + ex.Message); } }); m_timer.Start(); } #endregion private void btnTest_Click(object sender, EventArgs e) { try { DemoService demoService = new DemoService(); DemoService2 demoService2 = new DemoService2(); MessageBox.Show(demoService.Test("测试DemoService", 1) + "\r\n" + demoService2.RunTest("测试DemoService2", 2)); } catch (Exception ex) { LogUtil.LogError(ex.Message); MessageBox.Show(ex.Message); } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { m_timer.Stop(); if (ServiceUtil.clientSocket != null) { if (ServiceUtil.clientSocket.Connected) ServiceUtil.clientSocket.Disconnect(false); ServiceUtil.clientSocket.Close(); ServiceUtil.clientSocket.Dispose(); } } } }
时间: 2024-11-08 23:33:14