C# 异步 TCP 服务器完整实现
2013-04-14 19:33
381 查看
TCP异步Socket模型
C#的TCP异步Socket模型是通过Begin-End模式实现的。例如提供 BeginConnect、BeginAccept、BeginSend 和 BeginReceive等。IAsyncResult BeginAccept(AsyncCallback callback, object state);
AsyncCallback 回调在函数执行完毕后执行。state 对象被用于在执行函数和回调函数间传输信息。
Socket socket = new Socket( AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); IPEndPoint iep = new IPEndPoint(IPAddress.Any, 8888); socket.Bind(iep); socket.Listen(5); socket.BeginAccept (new AsyncCallback(CallbackAccept), socket); private void CallbackAccept(IAsyncResult iar) { Socket server = (Socket)iar.AsyncState; Socket client = server.EndAccept(iar); }
则在Accept一个TcpClient,需要维护TcpClient列表。
private List<TcpClientState> clients;
异步TCP服务器完整实现
/// <summary> /// 异步TCP服务器 /// </summary> public class AsyncTcpServer : IDisposable { #region Fields private TcpListener listener; private List<TcpClientState> clients; private bool disposed = false; #endregion #region Ctors /// <summary> /// 异步TCP服务器 /// </summary> /// <param name="listenPort">监听的端口</param> public AsyncTcpServer(int listenPort) : this(IPAddress.Any, listenPort) { } /// <summary> /// 异步TCP服务器 /// </summary> /// <param name="localEP">监听的终结点</param> public AsyncTcpServer(IPEndPoint localEP) : this(localEP.Address, localEP.Port) { } /// <summary> /// 异步TCP服务器 /// </summary> /// <param name="localIPAddress">监听的IP地址</param> /// <param name="listenPort">监听的端口</param> public AsyncTcpServer(IPAddress localIPAddress, int listenPort) { Address = localIPAddress; Port = listenPort; this.Encoding = Encoding.Default; clients = new List<TcpClientState>(); listener = new TcpListener(Address, Port); listener.AllowNatTraversal(true); } #endregion #region Properties /// <summary> /// 服务器是否正在运行 /// </summary> public bool IsRunning { get; private set; } /// <summary> /// 监听的IP地址 /// </summary> public IPAddress Address { get; private set; } /// <summary> /// 监听的端口 /// </summary> public int Port { get; private set; } /// <summary> /// 通信使用的编码 /// </summary> public Encoding Encoding { get; set; } #endregion #region Server /// <summary> /// 启动服务器 /// </summary> /// <returns>异步TCP服务器</returns> public AsyncTcpServer Start() { if (!IsRunning) { IsRunning = true; listener.Start(); listener.BeginAcceptTcpClient( new AsyncCallback(HandleTcpClientAccepted), listener); } return this; } /// <summary> /// 启动服务器 /// </summary> /// <param name="backlog"> /// 服务器所允许的挂起连接序列的最大长度 /// </param> /// <returns>异步TCP服务器</returns> public AsyncTcpServer Start(int backlog) { if (!IsRunning) { IsRunning = true; listener.Start(backlog); listener.BeginAcceptTcpClient( new AsyncCallback(HandleTcpClientAccepted), listener); } return this; } /// <summary> /// 停止服务器 /// </summary> /// <returns>异步TCP服务器</returns> public AsyncTcpServer Stop() { if (IsRunning) { IsRunning = false; listener.Stop(); lock (this.clients) { for (int i = 0; i < this.clients.Count; i++) { this.clients[i].TcpClient.Client.Disconnect(false); } this.clients.Clear(); } } return this; } #endregion #region Receive private void HandleTcpClientAccepted(IAsyncResult ar) { if (IsRunning) { TcpListener tcpListener = (TcpListener)ar.AsyncState; TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar); byte[] buffer = new byte[tcpClient.ReceiveBufferSize]; TcpClientState internalClient = new TcpClientState(tcpClient, buffer); lock (this.clients) { this.clients.Add(internalClient); RaiseClientConnected(tcpClient); } NetworkStream networkStream = internalClient.NetworkStream; networkStream.BeginRead( internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient); tcpListener.BeginAcceptTcpClient( new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState); } } private void HandleDatagramReceived(IAsyncResult ar) { if (IsRunning) { TcpClientState internalClient = (TcpClientState)ar.AsyncState; NetworkStream networkStream = internalClient.NetworkStream; int numberOfReadBytes = 0; try { numberOfReadBytes = networkStream.EndRead(ar); } catch { numberOfReadBytes = 0; } if (numberOfReadBytes == 0) { // connection has been closed lock (this.clients) { this.clients.Remove(internalClient); RaiseClientDisconnected(internalClient.TcpClient); return; } } // received byte and trigger event notification byte[] receivedBytes = new byte[numberOfReadBytes]; Buffer.BlockCopy( internalClient.Buffer, 0, receivedBytes, 0, numberOfReadBytes); RaiseDatagramReceived(internalClient.TcpClient, receivedBytes); RaisePlaintextReceived(internalClient.TcpClient, receivedBytes); // continue listening for tcp datagram packets networkStream.BeginRead( internalClient.Buffer, 0, internalClient.Buffer.Length, HandleDatagramReceived, internalClient); } } #endregion #region Events /// <summary> /// 接收到数据报文事件 /// </summary> public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived; /// <summary> /// 接收到数据报文明文事件 /// </summary> public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived; private void RaiseDatagramReceived(TcpClient sender, byte[] datagram) { if (DatagramReceived != null) { DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram)); } } private void RaisePlaintextReceived(TcpClient sender, byte[] datagram) { if (PlaintextReceived != null) { PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>( sender, this.Encoding.GetString(datagram, 0, datagram.Length))); } } /// <summary> /// 与客户端的连接已建立事件 /// </summary> public event EventHandler<TcpClientConnectedEventArgs> ClientConnected; /// <summary> /// 与客户端的连接已断开事件 /// </summary> public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected; private void RaiseClientConnected(TcpClient tcpClient) { if (ClientConnected != null) { ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient)); } } private void RaiseClientDisconnected(TcpClient tcpClient) { if (ClientDisconnected != null) { ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient)); } } #endregion #region Send /// <summary> /// 发送报文至指定的客户端 /// </summary> /// <param name="tcpClient">客户端</param> /// <param name="datagram">报文</param> public void Send(TcpClient tcpClient, byte[] datagram) { if (!IsRunning) throw new InvalidProgramException("This TCP server has not been started."); if (tcpClient == null) throw new ArgumentNullException("tcpClient"); if (datagram == null) throw new ArgumentNullException("datagram"); tcpClient.GetStream().BeginWrite( datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient); } private void HandleDatagramWritten(IAsyncResult ar) { ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar); } /// <summary> /// 发送报文至指定的客户端 /// </summary> /// <param name="tcpClient">客户端</param> /// <param name="datagram">报文</param> public void Send(TcpClient tcpClient, string datagram) { Send(tcpClient, this.Encoding.GetBytes(datagram)); } /// <summary> /// 发送报文至所有客户端 /// </summary> /// <param name="datagram">报文</param> public void SendAll(byte[] datagram) { if (!IsRunning) throw new InvalidProgramException("This TCP server has not been started."); for (int i = 0; i < this.clients.Count; i++) { Send(this.clients[i].TcpClient, datagram); } } /// <summary> /// 发送报文至所有客户端 /// </summary> /// <param name="datagram">报文</param> public void SendAll(string datagram) { if (!IsRunning) throw new InvalidProgramException("This TCP server has not been started."); SendAll(this.Encoding.GetBytes(datagram)); } #endregion #region IDisposable Members /// <summary> /// Performs application-defined tasks associated with freeing, /// releasing, or resetting unmanaged resources. /// </summary> public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } /// <summary> /// Releases unmanaged and - optionally - managed resources /// </summary> /// <param name="disposing"><c>true</c> to release /// both managed and unmanaged resources; <c>false</c> /// to release only unmanaged resources.</param> protected virtual void Dispose(bool disposing) { if (!this.disposed) { if (disposing) { try { Stop(); if (listener != null) { listener = null; } } catch (SocketException ex) { ExceptionHandler.Handle(ex); } } disposed = true; } } #endregion }
使用举例
class Program { static AsyncTcpServer server; static void Main(string[] args) { LogFactory.Assign(new ConsoleLogFactory()); server = new AsyncTcpServer(9999); server.Encoding = Encoding.UTF8; server.ClientConnected += new EventHandler<TcpClientConnectedEventArgs>(server_ClientConnected); server.ClientDisconnected += new EventHandler<TcpClientDisconnectedEventArgs>(server_ClientDisconnected); server.PlaintextReceived += new EventHandler<TcpDatagramReceivedEventArgs<string>>(server_PlaintextReceived); server.Start(); Console.WriteLine("TCP server has been started."); Console.WriteLine("Type something to send to client..."); while (true) { string text = Console.ReadLine(); server.SendAll(text); } } static void server_ClientConnected(object sender, TcpClientConnectedEventArgs e) { Logger.Debug(string.Format(CultureInfo.InvariantCulture, "TCP client {0} has connected.", e.TcpClient.Client.RemoteEndPoint.ToString())); } static void server_ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e) { Logger.Debug(string.Format(CultureInfo.InvariantCulture, "TCP client {0} has disconnected.", e.TcpClient.Client.RemoteEndPoint.ToString())); } static void server_PlaintextReceived(object sender, TcpDatagramReceivedEventArgs<string> e) { if (e.Datagram != "Received") { Console.Write(string.Format("Client : {0} --> ", e.TcpClient.Client.RemoteEndPoint.ToString())); Console.WriteLine(string.Format("{0}", e.Datagram)); server.Send(e.TcpClient, "Server has received you text : " + e.Datagram); } } }
[b]本文为 Dennis Gao 原创技术文章,发表于博客园博客,未经作者本人允许禁止任何形式的转载。[/b]
相关文章推荐
- C#异步TCP服务器完整实现
- C#异步TCP服务器完整实现
- C#异步TCP服务器完整实现
- C#网络编程系列文章(一)之Socket实现异步TCP服务器
- C#网络编程系列文章(一)之Socket实现异步TCP服务器
- c#异步Socket Tcp服务器实现
- C#网络编程系列文章(三)之TcpListener实现异步TCP服务器
- C# 异步 TCP 通信完整实现
- C#网络编程系列文章(一)之Socket实现异步TCP服务器
- C#网络编程系列文章(三)之TcpListener实现异步TCP服务器
- C#网络编程系列文章(七)之UdpClient实现异步UDP服务器
- C#实现SMTP服务器,使用TCP命令实现,功能比较完善
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)----使用方法
- 在C#中使用异步Socket编程实现TCP网络服务的C/S的通讯构架(二)----使用方法
- C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)
- 基于C#的socket编程的TCP异步实现
- 基于C#的socket编程的TCP异步实现 ,包含服务器端与客户端源代码
- C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)
- C#完整的通信代码(点对点,点对多,同步,异步,UDP,TCP)
- 基于C#的socket编程的TCP异步实现