C#实现异步阻塞TCP(Send,Receive,Accept,Connect)
1.类
(1)服务器端操作类
public class TcpServiceSocket { //接收数据事件 public Action<Socket, string> recvMessageEvent = null; //发送结果事件 public Action<int> sendResultEvent = null; //允许连接到tcp服务器的tcp客户端数量 private int numConnections = 0; //连接socket private Socket listenSocket = null; //tcp服务器ip private string host = ""; //tcp服务器端口 private int port = 0; //控制tcp客户端连接数量的信号量 private Semaphore maxNumberAcceptedClients = null; private int bufferSize = 1024; private List<Socket> clientSockets = null; public TcpServiceSocket(string host, int port, int numConnections) { if (string.IsNullOrEmpty(host)) throw new ArgumentNullException("host cannot be null"); if (port < 1 || port > 65535) throw new ArgumentOutOfRangeException("port is out of range"); if (numConnections <= 0 || numConnections > int.MaxValue) throw new ArgumentOutOfRangeException("_numConnections is out of range"); this.host = host; this.port = port; this.numConnections = numConnections; clientSockets = new List<Socket>(); maxNumberAcceptedClients = new Semaphore(numConnections, numConnections); } public void Start() { try { listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listenSocket.Bind(new IPEndPoint(IPAddress.Parse(host), port)); listenSocket.Listen(numConnections); AcceptAsync(); } catch (Exception) { } } private async void AcceptAsync() { await Task.Run(new Action(() => { while (true) { maxNumberAcceptedClients.WaitOne(); try { Socket acceptSocket = listenSocket.Accept(); if (acceptSocket == null) continue; clientSockets.Add(acceptSocket); RecvAsync(acceptSocket); } catch (Exception) { maxNumberAcceptedClients.Release(); } } })); } private async void RecvAsync(Socket acceptSocket) { await Task.Run(new Action(() => { int len = 0; byte[] buffer = new byte[bufferSize]; try { while ((len = acceptSocket.Receive(buffer, bufferSize, SocketFlags.None)) > 0) { if (recvMessageEvent != null) recvMessageEvent(acceptSocket, Encoding.UTF8.GetString(buffer, 0, len)); } } catch (Exception) { CloseClientSocket(acceptSocket); } })); } public async void SendAsync(Socket acceptSocket, string message) { await Task.Run(new Action(() => { int len = 0; byte[] buffer = Encoding.UTF8.GetBytes(message); try { if ((len = acceptSocket.Send(buffer, buffer.Length, SocketFlags.None)) > 0) { if (sendResultEvent != null) sendResultEvent(len); } } catch (Exception) { CloseClientSocket(acceptSocket); } })); } public async void SendMessageToAllClientsAsync(string message) { await Task.Run(new Action(() => { foreach (var socket in clientSockets) { SendAsync(socket, message); } })); } private void CloseClientSocket(Socket acceptSocket) { try { acceptSocket.Shutdown(SocketShutdown.Both); } catch { } try { acceptSocket.Close(); } catch { } maxNumberAcceptedClients.Release(); } public void CloseAllClientSocket(Socket acceptSocket) { try { foreach (var socket in clientSockets) { socket.Shutdown(SocketShutdown.Both); } } catch { } try { foreach (var socket in clientSockets) { socket.Close(); } } catch { } try { listenSocket.Shutdown(SocketShutdown.Both); } catch { } try { listenSocket.Close(); } catch { } try { maxNumberAcceptedClients.Release(clientSockets.Count); clientSockets.Clear(); } catch { } } }
(2)客户端操作类
public class TcpClientSocket { //接收数据事件 public Action<string> recvMessageEvent = null; //发送结果事件 public Action<int> sendResultEvent = null; //连接socket private Socket connectSocket = null; //tcp服务器ip private string host = ""; //tcp服务器端口 private int port = 0; private int bufferSize = 1024; public TcpClientSocket(string host, int port) { if (string.IsNullOrEmpty(host)) throw new ArgumentNullException("host cannot be null"); if (port < 1 || port > 65535) throw new ArgumentOutOfRangeException("port is out of range"); this.host = host; this.port = port; } public void Start() { try { connectSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); connectSocket.Connect(host, port); RecvAsync(); } catch (Exception) { } } private async void RecvAsync() { await Task.Run(new Action(() => { int len = 0; byte[] buffer = new byte[bufferSize]; try { while ((len = connectSocket.Receive(buffer, bufferSize, SocketFlags.None)) > 0) { if (recvMessageEvent != null) recvMessageEvent(Encoding.UTF8.GetString(buffer, 0, len)); } } catch (Exception) { Restart(); } })); } public async void SendAsync(string message) { await Task.Run(new Action(() => { int len = 0; byte[] buffer = Encoding.UTF8.GetBytes(message); try { if ((len = connectSocket.Send(buffer, buffer.Length, SocketFlags.None)) > 0) { if (sendResultEvent != null) sendResultEvent(len); } } catch (Exception) { Restart(); } })); } public void CloseClientSocket() { try { connectSocket.Shutdown(SocketShutdown.Both); } catch { } try { connectSocket.Close(); } catch { } } public void Restart() { CloseClientSocket(); Start(); } }
2.使用
(1)服务器:
public partial class Form1 : Form { TcpServiceSocket tcpServiceSocket = null; private readonly string ip = "192.168.172.142"; private readonly int port = 8090; public Form1() { InitializeComponent(); tcpServiceSocket = new TcpServiceSocket(ip, port, 10); tcpServiceSocket.recvMessageEvent += new Action<Socket, string>(Recv); } private void Recv(Socket socket, string message) { this.BeginInvoke(new Action(() => { tbRecv.Text += message + "\r\n"; })); } private void btnStart_Click(object sender, EventArgs e) { tcpServiceSocket.Start(); } private void btnSend_Click(object sender, EventArgs e) { string message = tbSend.Text.Trim(); if (string.IsNullOrEmpty(message)) return; tcpServiceSocket.SendMessageToAllClientsAsync(message); tbSend.Text = ""; } }
(2)客户端
public partial class Form1 : Form { private TcpClientSocket tcpClientSocket = null; private readonly string ip = "192.168.172.142"; private readonly int port = 8090; public Form1() { InitializeComponent(); tcpClientSocket = new TcpClientSocket(ip, port); tcpClientSocket.recvMessageEvent += new Action<string>(Recv); } private void Recv(string message) { this.BeginInvoke(new Action(() => { tbRecv.Text += message + "\r\n"; })); } private void btnStart_Click(object sender, EventArgs e) { tcpClientSocket.Start(); } private void btnSend_Click(object sender, EventArgs e) { string message = tbSend.Text.Trim(); if (string.IsNullOrEmpty(message)) return; tcpClientSocket.SendAsync(message); tbSend.Text = ""; } }