C# .NET Socket封裝,
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
}
}
View Code
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; }
}
}
View Code
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);
}
}
}
View Code
二、服務端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
}
}
View Code
三、服務端的服務接口類:
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;
}
}
}
View Code
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;
}
}
}
View Code
三、客戶端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);
}
}
}
View Code
六、客戶端接口類代碼:
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 });
}
}
}
View Code
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();
}
}
}
View Code
六:客戶端測試代碼:

![]()
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();
}
}
}
}
View Code