C#网络编程系列文章(三)之TcpListener实现异步TCP服务器

来源:互联网 发布:js e.currenttarget 编辑:程序博客网 时间:2024/05/16 09:27

原创性声明

本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处

文章系列目录

C#网络编程系列文章(一)之Socket实现异步TCP服务器 

C#网络编程系列文章(二)之Socket实现同步TCP服务器

C#网络编程系列文章(三)之TcpListener实现异步TCP服务器

C#网络编程系列文章(四)之TcpListener实现同步TCP服务器

C#网络编程系列文章(五)之Socket实现异步UDP服务器

C#网络编程系列文章(六)之Socket实现同步UDP服务器

C#网络编程系列文章(七)之UdpClient实现异步UDP服务器

C#网络编程系列文章(八)之UdpClient实现同步UDP服务器


本文介绍

TcpListener 类提供一些简单方法,用于在阻止同步模式下侦听和接受传入连接请求。 可使用 TcpClient 或 Socket 来连接 TcpListener。 可使用 IPEndPoint、本地 IP 地址及端口号或者仅使用端口号,来创建 TcpListener。 可以将本地 IP 地址指定为 Any,将本地端口号指定为 0(如果希望基础服务提供程序为您分配这些值)。 如果您选择这样做,可在连接套接字后使用 LocalEndpoint 属性来标识已指定的信息。使用 Start 方法,可开始侦听传入的连接请求。 Start 将对传入连接进行排队,直至您调用 Stop 方法或它已经完成 MaxConnections 排队为止。 可使用 AcceptSocket 或 AcceptTcpClient 从传入连接请求队列提取连接。 这两种方法将阻止。 如果要避免阻止,可首先使用 Pending 方法来确定队列中是否有可用的连接请求。

虽然TcpListener已经封装的比较不错了,我们于是就使用它在构造一个比较不错的异步TCP服务器,这里依然和前两章一样,给出服务器中的代码,代码中注释很详细,我也会给出相关的封装类。

TcpListener异步TCP服务器

服务器代码
[csharp] view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Net.Sockets;  
  6. using System.Net;  
  7. namespace NetFrame.Net.TCP.Listener.Asynchronous  
  8. {  
  9.     /// <summary>  
  10.     /// TcpListener实现异步TCP服务器  
  11.     /// </summary>  
  12.     public class AsyncTCPServer : IDisposable  
  13.     {  
  14.         #region Fields  
  15.         /// <summary>  
  16.         /// 服务器程序允许的最大客户端连接数  
  17.         /// </summary>  
  18.         private int _maxClient;  
  19.   
  20.         /// <summary>  
  21.         /// 当前的连接的客户端数  
  22.         /// </summary>  
  23.         private int _clientCount;  
  24.   
  25.         /// <summary>  
  26.         /// 服务器使用的异步TcpListener  
  27.         /// </summary>  
  28.         private TcpListener _listener;  
  29.   
  30.         /// <summary>  
  31.         /// 客户端会话列表  
  32.         /// </summary>  
  33.         private List<Object> _clients;  
  34.   
  35.         private bool disposed = false;  
  36.  
  37.         #endregion  
  38.  
  39.         #region Properties  
  40.   
  41.         /// <summary>  
  42.         /// 服务器是否正在运行  
  43.         /// </summary>  
  44.         public bool IsRunning { getprivate set; }  
  45.         /// <summary>  
  46.         /// 监听的IP地址  
  47.         /// </summary>  
  48.         public IPAddress Address { getprivate set; }  
  49.         /// <summary>  
  50.         /// 监听的端口  
  51.         /// </summary>  
  52.         public int Port { getprivate set; }  
  53.         /// <summary>  
  54.         /// 通信使用的编码  
  55.         /// </summary>  
  56.         public Encoding Encoding { getset; }  
  57.  
  58.  
  59.         #endregion  
  60.  
  61.         #region 构造函数  
  62.   
  63.         /// <summary>  
  64.         /// 异步TCP服务器  
  65.         /// </summary>  
  66.         /// <param name="listenPort">监听的端口</param>  
  67.         public AsyncTCPServer(int listenPort)  
  68.             : this(IPAddress.Any, listenPort)  
  69.         {  
  70.         }  
  71.   
  72.         /// <summary>  
  73.         /// 异步TCP服务器  
  74.         /// </summary>  
  75.         /// <param name="localEP">监听的终结点</param>  
  76.         public AsyncTCPServer(IPEndPoint localEP)  
  77.             : this(localEP.Address, localEP.Port)  
  78.         {  
  79.         }  
  80.   
  81.         /// <summary>  
  82.         /// 异步TCP服务器  
  83.         /// </summary>  
  84.         /// <param name="localIPAddress">监听的IP地址</param>  
  85.         /// <param name="listenPort">监听的端口</param>  
  86.         public AsyncTCPServer(IPAddress localIPAddress, int listenPort)  
  87.         {  
  88.             Address = localIPAddress;  
  89.             Port = listenPort;  
  90.             this.Encoding = Encoding.Default;  
  91.   
  92.             _clients = new List<Object>();  
  93.   
  94.             _listener = new TcpListener(Address, Port);  
  95.             _listener.AllowNatTraversal(true);  
  96.         }  
  97.  
  98.         #endregion  
  99.  
  100.         #region Method  
  101.   
  102.         /// <summary>  
  103.         /// 启动服务器  
  104.         /// </summary>  
  105.         public void Start()  
  106.         {  
  107.             if (!IsRunning)  
  108.             {  
  109.                 IsRunning = true;  
  110.                 _listener.Start();  
  111.                 _listener.BeginAcceptTcpClient(  
  112.                   new AsyncCallback(HandleTcpClientAccepted), _listener);  
  113.             }  
  114.         }  
  115.   
  116.   
  117.         /// <summary>  
  118.         /// 启动服务器  
  119.         /// </summary>  
  120.         /// <param name="backlog">  
  121.         /// 服务器所允许的挂起连接序列的最大长度  
  122.         /// </param>  
  123.         public void Start(int backlog)  
  124.         {  
  125.             if (!IsRunning)  
  126.             {  
  127.                 IsRunning = true;  
  128.                 _listener.Start(backlog);  
  129.                 _listener.BeginAcceptTcpClient(  
  130.                   new AsyncCallback(HandleTcpClientAccepted), _listener);  
  131.             }  
  132.         }  
  133.   
  134.         /// <summary>  
  135.         /// 停止服务器  
  136.         /// </summary>  
  137.         public void Stop()  
  138.         {  
  139.             if (IsRunning)  
  140.             {  
  141.                 IsRunning = false;  
  142.                 _listener.Stop();  
  143.                 lock (_clients)  
  144.                 {  
  145.                     //关闭所有客户端连接  
  146.                     CloseAllClient();  
  147.                 }  
  148.             }  
  149.         }  
  150.   
  151.         /// <summary>  
  152.         /// 处理客户端连接的函数  
  153.         /// </summary>  
  154.         /// <param name="ar"></param>  
  155.         private void HandleTcpClientAccepted(IAsyncResult ar)  
  156.         {  
  157.             if (IsRunning)  
  158.             {  
  159.                 //TcpListener tcpListener = (TcpListener)ar.AsyncState;  
  160.   
  161.                 TcpClient client = _listener.EndAcceptTcpClient(ar);  
  162.                 byte[] buffer = new byte[client.ReceiveBufferSize];  
  163.   
  164.                 TCPClientState state  
  165.                   = new TCPClientState(client, buffer);  
  166.                 lock (_clients)  
  167.                 {  
  168.                     _clients.Add(state);  
  169.                     RaiseClientConnected(state);  
  170.                 }  
  171.   
  172.                 NetworkStream stream = state.NetworkStream;  
  173.                 //开始异步读取数据  
  174.                 stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);  
  175.   
  176.                 _listener.BeginAcceptTcpClient(  
  177.                   new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);  
  178.             }  
  179.         }  
  180.         /// <summary>  
  181.         /// 数据接受回调函数  
  182.         /// </summary>  
  183.         /// <param name="ar"></param>  
  184.         private void HandleDataReceived(IAsyncResult ar)  
  185.         {  
  186.             if (IsRunning)  
  187.             {  
  188.                 TCPClientState state = (TCPClientState)ar.AsyncState;  
  189.                 NetworkStream stream = state.NetworkStream;  
  190.   
  191.                 int recv = 0;  
  192.                 try  
  193.                 {  
  194.                     recv = stream.EndRead(ar);  
  195.                 }  
  196.                 catch  
  197.                 {  
  198.                     recv = 0;  
  199.                 }  
  200.   
  201.                 if (recv == 0)  
  202.                 {  
  203.                     // connection has been closed  
  204.                     lock (_clients)  
  205.                     {  
  206.                         _clients.Remove(state);  
  207.                         //触发客户端连接断开事件  
  208.                         RaiseClientDisconnected(state);  
  209.                         return;  
  210.                     }  
  211.                 }  
  212.   
  213.                 // received byte and trigger event notification  
  214.                 byte[] buff = new byte[recv];  
  215.                 Buffer.BlockCopy(state.Buffer, 0, buff, 0, recv);  
  216.                 //触发数据收到事件  
  217.                 RaiseDataReceived(state);  
  218.   
  219.                 // continue listening for tcp datagram packets  
  220.                 stream.BeginRead(state.Buffer, 0, state.Buffer.Length, HandleDataReceived, state);  
  221.             }  
  222.         }  
  223.   
  224.         /// <summary>  
  225.         /// 发送数据  
  226.         /// </summary>  
  227.         /// <param name="state">接收数据的客户端会话</param>  
  228.         /// <param name="data">数据报文</param>  
  229.         public void Send(TCPClientState state, byte[] data)  
  230.         {  
  231.             RaisePrepareSend(state);  
  232.             Send(state.TcpClient, data);  
  233.         }  
  234.   
  235.         /// <summary>  
  236.         /// 异步发送数据至指定的客户端  
  237.         /// </summary>  
  238.         /// <param name="client">客户端</param>  
  239.         /// <param name="data">报文</param>  
  240.         public void Send(TcpClient client, byte[] data)  
  241.         {  
  242.             if (!IsRunning)  
  243.                 throw new InvalidProgramException("This TCP Scoket server has not been started.");  
  244.   
  245.             if (client == null)  
  246.                 throw new ArgumentNullException("client");  
  247.   
  248.             if (data == null)  
  249.                 throw new ArgumentNullException("data");  
  250.             client.GetStream().BeginWrite(data, 0, data.Length, SendDataEnd, client);  
  251.         }  
  252.   
  253.         /// <summary>  
  254.         /// 发送数据完成处理函数  
  255.         /// </summary>  
  256.         /// <param name="ar">目标客户端Socket</param>  
  257.         private void SendDataEnd(IAsyncResult ar)  
  258.         {  
  259.             ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);  
  260.             RaiseCompletedSend(null);  
  261.         }  
  262.         #endregion  
  263.  
  264.         #region 事件  
  265.   
  266.         /// <summary>  
  267.         /// 与客户端的连接已建立事件  
  268.         /// </summary>  
  269.         public event EventHandler<AsyncEventArgs> ClientConnected;  
  270.         /// <summary>  
  271.         /// 与客户端的连接已断开事件  
  272.         /// </summary>  
  273.         public event EventHandler<AsyncEventArgs> ClientDisconnected;  
  274.   
  275.   
  276.         /// <summary>  
  277.         /// 触发客户端连接事件  
  278.         /// </summary>  
  279.         /// <param name="state"></param>  
  280.         private void RaiseClientConnected(TCPClientState state)  
  281.         {  
  282.             if (ClientConnected != null)  
  283.             {  
  284.                 ClientConnected(thisnew AsyncEventArgs(state));  
  285.             }  
  286.         }  
  287.         /// <summary>  
  288.         /// 触发客户端连接断开事件  
  289.         /// </summary>  
  290.         /// <param name="client"></param>  
  291.         private void RaiseClientDisconnected(TCPClientState state)  
  292.         {  
  293.             if (ClientDisconnected != null)  
  294.             {  
  295.                 ClientDisconnected(thisnew AsyncEventArgs("连接断开"));  
  296.             }  
  297.         }  
  298.   
  299.         /// <summary>  
  300.         /// 接收到数据事件  
  301.         /// </summary>  
  302.         public event EventHandler<AsyncEventArgs> DataReceived;  
  303.   
  304.         private void RaiseDataReceived(TCPClientState state)  
  305.         {  
  306.             if (DataReceived != null)  
  307.             {  
  308.                 DataReceived(thisnew AsyncEventArgs(state));  
  309.             }  
  310.         }  
  311.   
  312.         /// <summary>  
  313.         /// 发送数据前的事件  
  314.         /// </summary>  
  315.         public event EventHandler<AsyncEventArgs> PrepareSend;  
  316.   
  317.         /// <summary>  
  318.         /// 触发发送数据前的事件  
  319.         /// </summary>  
  320.         /// <param name="state"></param>  
  321.         private void RaisePrepareSend(TCPClientState state)  
  322.         {  
  323.             if (PrepareSend != null)  
  324.             {  
  325.                 PrepareSend(thisnew AsyncEventArgs(state));  
  326.             }  
  327.         }  
  328.   
  329.         /// <summary>  
  330.         /// 数据发送完毕事件  
  331.         /// </summary>  
  332.         public event EventHandler<AsyncEventArgs> CompletedSend;  
  333.   
  334.         /// <summary>  
  335.         /// 触发数据发送完毕的事件  
  336.         /// </summary>  
  337.         /// <param name="state"></param>  
  338.         private void RaiseCompletedSend(TCPClientState state)  
  339.         {  
  340.             if (CompletedSend != null)  
  341.             {  
  342.                 CompletedSend(thisnew AsyncEventArgs(state));  
  343.             }  
  344.         }  
  345.   
  346.         /// <summary>  
  347.         /// 网络错误事件  
  348.         /// </summary>  
  349.         public event EventHandler<AsyncEventArgs> NetError;  
  350.         /// <summary>  
  351.         /// 触发网络错误事件  
  352.         /// </summary>  
  353.         /// <param name="state"></param>  
  354.         private void RaiseNetError(TCPClientState state)  
  355.         {  
  356.             if (NetError != null)  
  357.             {  
  358.                 NetError(thisnew AsyncEventArgs(state));  
  359.             }  
  360.         }  
  361.   
  362.         /// <summary>  
  363.         /// 异常事件  
  364.         /// </summary>  
  365.         public event EventHandler<AsyncEventArgs> OtherException;  
  366.         /// <summary>  
  367.         /// 触发异常事件  
  368.         /// </summary>  
  369.         /// <param name="state"></param>  
  370.         private void RaiseOtherException(TCPClientState state, string descrip)  
  371.         {  
  372.             if (OtherException != null)  
  373.             {  
  374.                 OtherException(thisnew AsyncEventArgs(descrip, state));  
  375.             }  
  376.         }  
  377.         private void RaiseOtherException(TCPClientState state)  
  378.         {  
  379.             RaiseOtherException(state, "");  
  380.         }  
  381.  
  382.         #endregion  
  383.  
  384.         #region Close  
  385.         /// <summary>  
  386.         /// 关闭一个与客户端之间的会话  
  387.         /// </summary>  
  388.         /// <param name="state">需要关闭的客户端会话对象</param>  
  389.         public void Close(TCPClientState state)  
  390.         {  
  391.             if (state != null)  
  392.             {  
  393.                 state.Close();  
  394.                 _clients.Remove(state);  
  395.                 _clientCount--;  
  396.                 //TODO 触发关闭事件  
  397.             }  
  398.         }  
  399.         /// <summary>  
  400.         /// 关闭所有的客户端会话,与所有的客户端连接会断开  
  401.         /// </summary>  
  402.         public void CloseAllClient()  
  403.         {  
  404.             foreach (TCPClientState client in _clients)  
  405.             {  
  406.                 Close(client);  
  407.             }  
  408.             _clientCount = 0;  
  409.             _clients.Clear();  
  410.         }  
  411.         #endregion  
  412.  
  413.         #region 释放  
  414.         /// <summary>  
  415.         /// Performs application-defined tasks associated with freeing,   
  416.         /// releasing, or resetting unmanaged resources.  
  417.         /// </summary>  
  418.         public void Dispose()  
  419.         {  
  420.             Dispose(true);  
  421.             GC.SuppressFinalize(this);  
  422.         }  
  423.   
  424.         /// <summary>  
  425.         /// Releases unmanaged and - optionally - managed resources  
  426.         /// </summary>  
  427.         /// <param name="disposing"><c>true</c> to release   
  428.         /// both managed and unmanaged resources; <c>false</c>   
  429.         /// to release only unmanaged resources.</param>  
  430.         protected virtual void Dispose(bool disposing)  
  431.         {  
  432.             if (!this.disposed)  
  433.             {  
  434.                 if (disposing)  
  435.                 {  
  436.                     try  
  437.                     {  
  438.                         Stop();  
  439.                         if (_listener != null)  
  440.                         {  
  441.                             _listener = null;  
  442.                         }  
  443.                     }  
  444.                     catch (SocketException)  
  445.                     {  
  446.                         //TODO  
  447.                         RaiseOtherException(null);  
  448.                     }  
  449.                 }  
  450.                 disposed = true;  
  451.             }  
  452.         }  
  453.         #endregion  
  454.     }  
  455. }  
客户端处理封装类
[csharp] view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5. using System.Net.Sockets;  
  6.   
  7. namespace NetFrame.Net.TCP.Listener.Asynchronous  
  8. {  
  9.     public class TCPClientState  
  10.     {  
  11.         /// <summary>  
  12.         /// 与客户端相关的TcpClient  
  13.         /// </summary>  
  14.         public TcpClient TcpClient { getprivate set; }  
  15.   
  16.         /// <summary>  
  17.         /// 获取缓冲区  
  18.         /// </summary>  
  19.         public byte[] Buffer { getprivate set; }  
  20.   
  21.         /// <summary>  
  22.         /// 获取网络流  
  23.         /// </summary>  
  24.         public NetworkStream NetworkStream  
  25.         {  
  26.             get { return TcpClient.GetStream(); }  
  27.         }  
  28.   
  29.         public TCPClientState(TcpClient tcpClient, byte[] buffer)  
  30.         {  
  31.             if (tcpClient == null)  
  32.                 throw new ArgumentNullException("tcpClient");  
  33.             if (buffer == null)  
  34.                 throw new ArgumentNullException("buffer");  
  35.   
  36.             this.TcpClient = tcpClient;  
  37.             this.Buffer = buffer;  
  38.         }  
  39.         /// <summary>  
  40.         /// 关闭  
  41.         /// </summary>  
  42.         public void Close()  
  43.         {  
  44.             //关闭数据的接受和发送  
  45.             TcpClient.Close();  
  46.             Buffer = null;  
  47.         }  
  48.     }  
  49. }  
服务器事件参数类
[csharp] view plain copy
  1. using System;  
  2. using System.Collections.Generic;  
  3. using System.Linq;  
  4. using System.Text;  
  5.   
  6. namespace NetFrame.Net.TCP.Listener.Asynchronous  
  7. {  
  8.     /// <summary>  
  9.     /// 异步TcpListener TCP服务器事件参数类   
  10.     /// </summary>  
  11.     public class AsyncEventArgs:EventArgs  
  12.     {  
  13.          /// <summary>  
  14.         /// 提示信息  
  15.         /// </summary>  
  16.         public string _msg;  
  17.   
  18.         /// <summary>  
  19.         /// 客户端状态封装类  
  20.         /// </summary>  
  21.         public TCPClientState _state;  
  22.   
  23.         /// <summary>  
  24.         /// 是否已经处理过了  
  25.         /// </summary>  
  26.         public bool IsHandled { getset; }  
  27.   
  28.         public AsyncEventArgs(string msg)  
  29.         {  
  30.             this._msg = msg;  
  31.             IsHandled = false;  
  32.         }  
  33.         public AsyncEventArgs(TCPClientState state)  
  34.         {  
  35.             this._state = state;  
  36.             IsHandled = false;  
  37.         }  
  38.         public AsyncEventArgs(string msg, TCPClientState state)  
  39.         {  
  40.             this._msg = msg;  
  41.             this._state = state;  
  42.             IsHandled = false;  
  43.         }  
  44.     }  
  45. }  

本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处
阅读全文
0 0