C#完成異步套接字封裝server與client處理方案 發表時間:2023-07-28 來源:明輝站整理相關軟件相關文章人氣: [摘要]C#實現異步套接字封裝server與client解決方案 之前一直用C#些了很多管理軟件,包括c/s , b/s ,之前一直都是同步寫法,相信大家都用ajax異步請求數據,那能不能實... C#實現異步套接字封裝server與client解決方案
之前一直用C#些了很多管理軟件,包括c/s , b/s ,之前一直都是同步寫法,相信大家都用ajax異步請求數據,那能不能實現 C#實現異步套接字封裝server與client 呢,答案是肯定的。
今天文章中寫的是異步,純粹的異步,當然很多人看來很簡單了,而且里面很多東西值得商榷,不過說真的,我真心感謝C#的線程池,不然我還要自己去寫個threadpool。而且我沒辦法保證我寫的沒問題。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Net.Sockets;
using System.Net;
using System.Threading;
namespace PPT.Comm
{
///
/// 接收數據流
///
/// 異步套接字
/// 接收到的數據流
public delegate void AsyncDataAcceptedEventHandler(AsyncSocket m_pSocket, byte[] m_pDatagram);
///
/// 發送完畢
///
/// 異步套接字
/// 發送結果
public delegate void AsyncDataSendedEventHandler(AsyncSocket m_pSocket, bool m_pIsSuccess);
///
/// 接收連接委托
///
/// 異步套接字
public delegate void AsyncSocketAcceptEventHandler(AsyncSocket m_pSocket);
///
/// 關閉連接委托
///
/// 異步套接字
public delegate void AsyncSocketClosedEventHandler(AsyncSocket m_pSocket);
///
/// State object for receiving data from remote device.
///
class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024 * 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
///
/// 異步SOCKET
///
public class AsyncSocket
{
#region 私有字段 成員
private Socket m_socket = null; //socket
string m_id = ""; //socket唯一標識,GUID
private readonly bool m_isSerevr; //服務器標志位
private int m_iBackBag;
private string m_ipAddress;
private int m_port;
private AsyncDataAcceptedEventHandler m_onAsyncDataAcceptedEvent = null; //接收數據流
private AsyncDataSendedEventHandler m_onAsyncDataSendedEvent = null; //發送結束
private AsyncSocketAcceptEventHandler m_onAsyncSocketAcceptEvent = null; //接收連接
private AsyncSocketClosedEventHandler m_onAsyncSocketClosedEvent = null; //關閉連接
#endregion
#region 公共屬性 成員
///
/// 獲取SOCKET標志位
///
public string ID
{
get
{
return m_id;
}
}
///
/// 設置或獲取機器標志位
///
public string MachineKey
{
set;
get;
}
///
/// 獲取、設置連接對象
///
public Socket LinkObject
{
get
{
return m_socket;
}
set
{
m_socket = value;
}
}
///
/// 設置或獲取線程退出標識
///
public bool IsExit { set; get; }
#endregion
#region 公共事件 成員
///
/// 連接關閉事件
///
public event AsyncSocketClosedEventHandler AsyncSocketClosedEvent
{
add
{
m_onAsyncSocketClosedEvent += value;
}
remove
{
m_onAsyncSocketClosedEvent -= value;
}
}
///
/// 連接接收事件
///
public event AsyncSocketAcceptEventHandler AsyncSocketAcceptEvent
{
add
{
m_onAsyncSocketAcceptEvent += value;
}
remove
{
m_onAsyncSocketAcceptEvent -= value;
}
}
///
/// 數據接收完成事件
///
public event AsyncDataAcceptedEventHandler AsyncDataAcceptedEvent
{
add
{
this.m_onAsyncDataAcceptedEvent += value;
}
remove
{
this.m_onAsyncDataAcceptedEvent -= value;
}
}
///
/// 數據發送完成事件
///
public event AsyncDataSendedEventHandler AsyncDataSendedEvent
{
add
{
m_onAsyncDataSendedEvent += value;
}
remove
{
m_onAsyncDataSendedEvent -= value;
}
}
#endregion
#region 構造函數 成員
///
/// 構造函數
///
/// 主機地址,可為機器名或者IP
/// 主機端口
/// 是否作為服務器,默認為false
/// 支持多少個客戶端
public AsyncSocket(string m_pHostAddrss, int m_pHostPort, bool m_pIsAsServer = false, int m_pIBackBag = 10)
{
m_isSerevr = m_pIsAsServer;
m_iBackBag = m_pIBackBag;
m_ipAddress = m_pHostAddrss;
m_port = m_pHostPort;
m_id = Guid.NewGuid().ToString();
}
///
/// 構造函數,用于服務器構造與客戶端的異步socket
///
/// 客戶端socket
private AsyncSocket(Socket linkObject)
{
m_socket = linkObject;
m_id = Guid.NewGuid().ToString();
}
#endregion
#region 公共方法
///
/// 打開通道
///
public void AsyncOpen()
{
if (m_isSerevr)
{
IPAddress ip = Dns.GetHostAddresses(m_ipAddress)[0];
IPEndPoint ipe = new IPEndPoint(ip, m_port);
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_socket.Bind(ipe);
m_socket.Listen(m_iBackBag);
m_socket.BeginAccept(new AsyncCallback(AcceptCallBack), null);//異步
}
else
{
IPAddress ip = Dns.GetHostAddresses(m_ipAddress)[0];
IPEndPoint ipe = new IPEndPoint(ip, m_port);
m_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
m_socket.Connect(ipe);
}
}
///
/// 發送二進制數據
///
///
public void AsyncSend(byte[] SendData)
{
m_socket.BeginSend(SendData, 0, SendData.Length, 0, new AsyncCallback(SendCallBack), m_socket);
}
///
/// 關閉通道
///
public void AsyncClose()
{
if (!m_isSerevr)
{
m_socket.Shutdown(SocketShutdown.Both);//關閉接收發送流
m_socket.BeginDisconnect(false, CloseCallBack, m_socket);//開始嘗試斷開
}
else
{
m_socket.Shutdown(SocketShutdown.Both);//關閉接收發送流
Thread.Sleep(200);//等待現有任務處理完成
m_socket.Dispose();//釋放所有本地資源
}
}
///
/// 開始接受數據,連接建立之后,調用此方法
///
public void BeginAcceptData()
{
//開始接收數據
StateObject state = new StateObject();
state.workSocket = m_socket;
m_socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
#endregion
#region 私有方法 成員
#endregion
#region 回調函數 成員
///
/// 接受客戶端連接處理
///
///
private void AcceptCallBack(IAsyncResult ar)
{
Socket handler = m_socket.EndAccept(ar);
AsyncSocket NewSocket = new AsyncSocket(handler);
//激發事件,異步觸發
if (m_onAsyncSocketAcceptEvent != null)
foreach (AsyncSocketAcceptEventHandler item in m_onAsyncSocketAcceptEvent.GetInvocationList())
item.BeginInvoke(NewSocket, null, null);
//繼續投遞監聽請求
m_socket.BeginAccept(new AsyncCallback(AcceptCallBack), null);
}
///
/// 接受字節流處理
///
///
private void ReceiveCallback(IAsyncResult ar)
{
try
{
StateObject state = ar.AsyncState as StateObject;
//讀取數據
int bytesRead = m_socket.EndReceive(ar);
if (bytesRead > 0)
{
byte[] _Readbyte = new byte[bytesRead];
Array.Copy(state.buffer, 0, _Readbyte, 0, bytesRead);
//接收完成,激發事件
if (m_onAsyncDataAcceptedEvent != null)
foreach (AsyncDataAcceptedEventHandler item in m_onAsyncDataAcceptedEvent.GetInvocationList())
item.BeginInvoke(this, _Readbyte, null, null);
state = new StateObject();//繼續投遞接收委托
state.workSocket = m_socket;
m_socket.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, new AsyncCallback(ReceiveCallback), state);
}
}
catch (SocketException)
{
if (m_onAsyncSocketClosedEvent != null)
foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(this, null, null);
}
}
///
/// 發送結束處理
///
///
private void SendCallBack(IAsyncResult ar)
{
try
{
m_socket.EndSend(ar);
if (m_onAsyncDataSendedEvent != null)
foreach (AsyncDataSendedEventHandler item in m_onAsyncDataSendedEvent.GetInvocationList())
item.BeginInvoke(this, true, null, null);
}
catch (SocketException)
{
if (m_onAsyncDataSendedEvent != null)
foreach (AsyncDataSendedEventHandler item in m_onAsyncDataSendedEvent.GetInvocationList())
item.BeginInvoke(this, false, null, null);
if (m_onAsyncSocketClosedEvent != null)
foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(this, null, null);
}
}
///
/// 關閉后處理
///
///
private void CloseCallBack(IAsyncResult ar)
{
try
{
m_socket.EndDisconnect(ar);
m_socket.Dispose();
if (m_onAsyncDataSendedEvent != null)
foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(this, null, null);
}
catch (SocketException)
{
if (m_onAsyncSocketClosedEvent != null)
foreach (AsyncSocketClosedEventHandler item in m_onAsyncSocketClosedEvent.GetInvocationList())
item.BeginInvoke(this, null, null);
}
}
#endregion
}
}
主要的代碼全部放出,注釋也寫的很詳細,當然不能保證我寫的代碼沒有問題,但是本人測試過,應該沒有打的問題。 學習教程快速掌握從入門到精通的電腦知識 | |