您的位置:首页 > 理论基础 > 计算机网络

C#异步TCP服务器完整实现

2013-04-14 22:41 701 查看

C#异步TCP服务器完整实现

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服务器完整实现



1   /// <summary>
2   /// 异步TCP服务器
3   /// </summary>
4   public class AsyncTcpServer : IDisposable
5   {
6     #region Fields
7
8     private TcpListener listener;
9     private List<TcpClientState> clients;
10     private bool disposed = false;
11
12     #endregion
13
14     #region Ctors
15
16     /// <summary>
17     /// 异步TCP服务器
18     /// </summary>
19     /// <param name="listenPort">监听的端口</param>
20     public AsyncTcpServer(int listenPort)
21       : this(IPAddress.Any, listenPort)
22     {
23     }
24
25     /// <summary>
26     /// 异步TCP服务器
27     /// </summary>
28     /// <param name="localEP">监听的终结点</param>
29     public AsyncTcpServer(IPEndPoint localEP)
30       : this(localEP.Address, localEP.Port)
31     {
32     }
33
34     /// <summary>
35     /// 异步TCP服务器
36     /// </summary>
37     /// <param name="localIPAddress">监听的IP地址</param>
38     /// <param name="listenPort">监听的端口</param>
39     public AsyncTcpServer(IPAddress localIPAddress, int listenPort)
40     {
41       Address = localIPAddress;
42       Port = listenPort;
43       this.Encoding = Encoding.Default;
44
45       clients = new List<TcpClientState>();
46
47       listener = new TcpListener(Address, Port);
48       listener.AllowNatTraversal(true);
49     }
50
51     #endregion
52
53     #region Properties
54
55     /// <summary>
56     /// 服务器是否正在运行
57     /// </summary>
58     public bool IsRunning { get; private set; }
59     /// <summary>
60     /// 监听的IP地址
61     /// </summary>
62     public IPAddress Address { get; private set; }
63     /// <summary>
64     /// 监听的端口
65     /// </summary>
66     public int Port { get; private set; }
67     /// <summary>
68     /// 通信使用的编码
69     /// </summary>
70     public Encoding Encoding { get; set; }
71
72     #endregion
73
74     #region Server
75
76     /// <summary>
77     /// 启动服务器
78     /// </summary>
79     /// <returns>异步TCP服务器</returns>
80     public AsyncTcpServer Start()
81     {
82       if (!IsRunning)
83       {
84         IsRunning = true;
85         listener.Start();
86         listener.BeginAcceptTcpClient(
87           new AsyncCallback(HandleTcpClientAccepted), listener);
88       }
89       return this;
90     }
91
92     /// <summary>
93     /// 启动服务器
94     /// </summary>
95     /// <param name="backlog">
96     /// 服务器所允许的挂起连接序列的最大长度
97     /// </param>
98     /// <returns>异步TCP服务器</returns>
99     public AsyncTcpServer Start(int backlog)
100     {
101       if (!IsRunning)
102       {
103         IsRunning = true;
104         listener.Start(backlog);
105         listener.BeginAcceptTcpClient(
106           new AsyncCallback(HandleTcpClientAccepted), listener);
107       }
108       return this;
109     }
110
111     /// <summary>
112     /// 停止服务器
113     /// </summary>
114     /// <returns>异步TCP服务器</returns>
115     public AsyncTcpServer Stop()
116     {
117       if (IsRunning)
118       {
119         IsRunning = false;
120         listener.Stop();
121
122         lock (this.clients)
123         {
124           for (int i = 0; i < this.clients.Count; i++)
125           {
126             this.clients[i].TcpClient.Client.Disconnect(false);
127           }
128           this.clients.Clear();
129         }
130
131       }
132       return this;
133     }
134
135     #endregion
136
137     #region Receive
138
139     private void HandleTcpClientAccepted(IAsyncResult ar)
140     {
141       if (IsRunning)
142       {
143         TcpListener tcpListener = (TcpListener)ar.AsyncState;
144
145         TcpClient tcpClient = tcpListener.EndAcceptTcpClient(ar);
146         byte[] buffer = new byte[tcpClient.ReceiveBufferSize];
147
148         TcpClientState internalClient
149           = new TcpClientState(tcpClient, buffer);
150         lock (this.clients)
151         {
152           this.clients.Add(internalClient);
153           RaiseClientConnected(tcpClient);
154         }
155
156         NetworkStream networkStream = internalClient.NetworkStream;
157         networkStream.BeginRead(
158           internalClient.Buffer,
159           0,
160           internalClient.Buffer.Length,
161           HandleDatagramReceived,
162           internalClient);
163
164         tcpListener.BeginAcceptTcpClient(
165           new AsyncCallback(HandleTcpClientAccepted), ar.AsyncState);
166       }
167     }
168
169     private void HandleDatagramReceived(IAsyncResult ar)
170     {
171       if (IsRunning)
172       {
173         TcpClientState internalClient = (TcpClientState)ar.AsyncState;
174         NetworkStream networkStream = internalClient.NetworkStream;
175
176         int numberOfReadBytes = 0;
177         try
178         {
179           numberOfReadBytes = networkStream.EndRead(ar);
180         }
181         catch
182         {
183           numberOfReadBytes = 0;
184         }
185
186         if (numberOfReadBytes == 0)
187         {
188           // connection has been closed
189           lock (this.clients)
190           {
191             this.clients.Remove(internalClient);
192             RaiseClientDisconnected(internalClient.TcpClient);
193             return;
194           }
195         }
196
197         // received byte and trigger event notification
198         byte[] receivedBytes = new byte[numberOfReadBytes];
199         Buffer.BlockCopy(
200           internalClient.Buffer, 0,
201           receivedBytes, 0, numberOfReadBytes);
202         RaiseDatagramReceived(internalClient.TcpClient, receivedBytes);
203         RaisePlaintextReceived(internalClient.TcpClient, receivedBytes);
204
205         // continue listening for tcp datagram packets
206         networkStream.BeginRead(
207           internalClient.Buffer,
208           0,
209           internalClient.Buffer.Length,
210           HandleDatagramReceived,
211           internalClient);
212       }
213     }
214
215     #endregion
216
217     #region Events
218
219     /// <summary>
220     /// 接收到数据报文事件
221     /// </summary>
222     public event EventHandler<TcpDatagramReceivedEventArgs<byte[]>> DatagramReceived;
223     /// <summary>
224     /// 接收到数据报文明文事件
225     /// </summary>
226     public event EventHandler<TcpDatagramReceivedEventArgs<string>> PlaintextReceived;
227
228     private void RaiseDatagramReceived(TcpClient sender, byte[] datagram)
229     {
230       if (DatagramReceived != null)
231       {
232         DatagramReceived(this, new TcpDatagramReceivedEventArgs<byte[]>(sender, datagram));
233       }
234     }
235
236     private void RaisePlaintextReceived(TcpClient sender, byte[] datagram)
237     {
238       if (PlaintextReceived != null)
239       {
240         PlaintextReceived(this, new TcpDatagramReceivedEventArgs<string>(
241           sender, this.Encoding.GetString(datagram, 0, datagram.Length)));
242       }
243     }
244
245     /// <summary>
246     /// 与客户端的连接已建立事件
247     /// </summary>
248     public event EventHandler<TcpClientConnectedEventArgs> ClientConnected;
249     /// <summary>
250     /// 与客户端的连接已断开事件
251     /// </summary>
252     public event EventHandler<TcpClientDisconnectedEventArgs> ClientDisconnected;
253
254     private void RaiseClientConnected(TcpClient tcpClient)
255     {
256       if (ClientConnected != null)
257       {
258         ClientConnected(this, new TcpClientConnectedEventArgs(tcpClient));
259       }
260     }
261
262     private void RaiseClientDisconnected(TcpClient tcpClient)
263     {
264       if (ClientDisconnected != null)
265       {
266         ClientDisconnected(this, new TcpClientDisconnectedEventArgs(tcpClient));
267       }
268     }
269
270     #endregion
271
272     #region Send
273
274     /// <summary>
275     /// 发送报文至指定的客户端
276     /// </summary>
277     /// <param name="tcpClient">客户端</param>
278     /// <param name="datagram">报文</param>
279     public void Send(TcpClient tcpClient, byte[] datagram)
280     {
281       if (!IsRunning)
282         throw new InvalidProgramException("This TCP server has not been started.");
283
284       if (tcpClient == null)
285         throw new ArgumentNullException("tcpClient");
286
287       if (datagram == null)
288         throw new ArgumentNullException("datagram");
289
290       tcpClient.GetStream().BeginWrite(
291         datagram, 0, datagram.Length, HandleDatagramWritten, tcpClient);
292     }
293
294     private void HandleDatagramWritten(IAsyncResult ar)
295     {
296       ((TcpClient)ar.AsyncState).GetStream().EndWrite(ar);
297     }
298
299     /// <summary>
300     /// 发送报文至指定的客户端
301     /// </summary>
302     /// <param name="tcpClient">客户端</param>
303     /// <param name="datagram">报文</param>
304     public void Send(TcpClient tcpClient, string datagram)
305     {
306       Send(tcpClient, this.Encoding.GetBytes(datagram));
307     }
308
309     /// <summary>
310     /// 发送报文至所有客户端
311     /// </summary>
312     /// <param name="datagram">报文</param>
313     public void SendAll(byte[] datagram)
314     {
315       if (!IsRunning)
316         throw new InvalidProgramException("This TCP server has not been started.");
317
318       for (int i = 0; i < this.clients.Count; i++)
319       {
320         Send(this.clients[i].TcpClient, datagram);
321       }
322     }
323
324     /// <summary>
325     /// 发送报文至所有客户端
326     /// </summary>
327     /// <param name="datagram">报文</param>
328     public void SendAll(string datagram)
329     {
330       if (!IsRunning)
331         throw new InvalidProgramException("This TCP server has not been started.");
332
333       SendAll(this.Encoding.GetBytes(datagram));
334     }
335
336     #endregion
337
338     #region IDisposable Members
339
340     /// <summary>
341     /// Performs application-defined tasks associated with freeing,
342     /// releasing, or resetting unmanaged resources.
343     /// </summary>
344     public void Dispose()
345     {
346       Dispose(true);
347       GC.SuppressFinalize(this);
348     }
349
350     /// <summary>
351     /// Releases unmanaged and - optionally - managed resources
352     /// </summary>
353     /// <param name="disposing"><c>true</c> to release
354     /// both managed and unmanaged resources; <c>false</c>
355     /// to release only unmanaged resources.</param>
356     protected virtual void Dispose(bool disposing)
357     {
358       if (!this.disposed)
359       {
360         if (disposing)
361         {
362           try
363           {
364             Stop();
365
366             if (listener != null)
367             {
368               listener = null;
369             }
370           }
371           catch (SocketException ex)
372           {
373             ExceptionHandler.Handle(ex);
374           }
375         }
376
377         disposed = true;
378       }
379     }
380
381     #endregion
382   }




使用举例



1   class Program
2   {
3     static AsyncTcpServer server;
4
5     static void Main(string[] args)
6     {
7       LogFactory.Assign(new ConsoleLogFactory());
8
9       server = new AsyncTcpServer(9999);
10       server.Encoding = Encoding.UTF8;
11       server.ClientConnected +=
12         new EventHandler<TcpClientConnectedEventArgs>(server_ClientConnected);
13       server.ClientDisconnected +=
14         new EventHandler<TcpClientDisconnectedEventArgs>(server_ClientDisconnected);
15       server.PlaintextReceived +=
16         new EventHandler<TcpDatagramReceivedEventArgs<string>>(server_PlaintextReceived);
17       server.Start();
18
19       Console.WriteLine("TCP server has been started.");
20       Console.WriteLine("Type something to send to client...");
21       while (true)
22       {
23         string text = Console.ReadLine();
24         server.SendAll(text);
25       }
26     }
27
28     static void server_ClientConnected(object sender, TcpClientConnectedEventArgs e)
29     {
30       Logger.Debug(string.Format(CultureInfo.InvariantCulture,
31         "TCP client {0} has connected.",
32         e.TcpClient.Client.RemoteEndPoint.ToString()));
33     }
34
35     static void server_ClientDisconnected(object sender, TcpClientDisconnectedEventArgs e)
36     {
37       Logger.Debug(string.Format(CultureInfo.InvariantCulture,
38         "TCP client {0} has disconnected.",
39         e.TcpClient.Client.RemoteEndPoint.ToString()));
40     }
41
42     static void server_PlaintextReceived(object sender, TcpDatagramReceivedEventArgs<string> e)
43     {
44       if (e.Datagram != "Received")
45       {
46         Console.Write(string.Format("Client : {0} --> ",
47           e.TcpClient.Client.RemoteEndPoint.ToString()));
48         Console.WriteLine(string.Format("{0}", e.Datagram));
49         server.Send(e.TcpClient, "Server has received you text : " + e.Datagram);
50       }
51     }
52   }


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: