服务端实现


异步传输字符串

在上一篇中,我们由简到繁,提到了服务端的四种方式:服务一个客户端的一个请求、服务一个客户端的多个请求、服务多个客户端的 一个请求、服务多个客 户端的多个请求。我们说到可以将里层的 while 循环交给一个新建的线程去让它来完成。除了这种方式以外, 我们还可以使用一种更好的方式――使用线程池中 的线程来完成。我们可以使用 BeginRead()、BeginWrite()等异步方法,同时让这 BeginRead()方法和它的回调方法形成一个类 似于 while 的无限循环:首先在第一层循环中,接收到一个客户端后,调用 BeginRead(), 然后为该方法提供一个读取完成后的回调方法,然后在回 调方法中对收到的字符进行处理,随后在回调方法中接着调用 BeginRead() 方法,并传入回调方法本身。 

由于程序实现功能和上一篇完全相同,我就不再细述了。而关于异步调用方法更多详细内容,可以参见 C#中的委托和事件(续)。

服务端的实现

当程序越来越复杂的时候,就需要越来越高的抽象,所以从现在起我们不再把所有的代码全部都扔进 Main()里,这次我创建了一个 RemoteClient 类,它对于服务端获取到的 TcpClient 进行了一个包装:

public class RemoteClient { 
 private TcpClient client; 
 private NetworkStream streamToClient; 
 private const int BufferSize = 8192; 
 private byte[] buffer; 
 private RequestHandler handler; 
 
 public RemoteClient(TcpClient client) { 
 this.client = client; 
 // 打印连接到的客户端信息
 Console.WriteLine("\nClient Connected!{0} <-- {1}", 
 client.Client.LocalEndPoint, client.Client.RemoteEndPoint); 
 // 获得流
 streamToClient = client.GetStream(); 
 buffer = new byte[BufferSize]; 
 // 设置 RequestHandler 
 handler = new RequestHandler(); 
 // 在构造函数中就开始准备读取
 AsyncCallback callBack = new AsyncCallback(ReadComplete); 
 streamToClient.BeginRead(buffer, 0, BufferSize, callBack, null); 
 } 
 // 再读取完成时进行回调
 private void ReadComplete(IAsyncResult ar) { 
 int bytesRead = 0; 
 try { 
 lock (streamToClient) { 
 bytesRead = streamToClient.EndRead(ar); 
 Console.WriteLine("Reading data, {0} bytes ...", bytesRead); 
 } 
 if (bytesRead == 0) throw new Exception("读取到 0 字节"); 
 string msg = Encoding.Unicode.GetString(buffer, 0, bytesRead); 
 Array.Clear(buffer,0,buffer.Length); // 清空缓存,避免脏读
 
 string[] msgArray = handler.GetActualString(msg); // 获取实际的字符串
 // 遍历获得到的字符串
 foreach (string m in msgArray) { 
 Console.WriteLine("Received: {0}", m); 
 string back = m.ToUpper(); 
 // 将得到的字符串改为大写并重新发送
 byte[] temp = Encoding.Unicode.GetBytes(back); 
 streamToClient.Write(temp, 0, temp.Length); 
 streamToClient.Flush(); 
 Console.WriteLine("Sent: {0}", back); 
 } 
 // 再次调用 BeginRead(),完成时调用自身,形成无限循环
 lock (streamToClient) { 
 AsyncCallback callBack = new AsyncCallback(ReadComplete); 
 streamToClient.BeginRead(buffer, 0, BufferSize, callBack, null); 
 } 
 } catch(Exception ex) { 
 if(streamToClient!=null) 
 streamToClient.Dispose(); 
 client.Close(); 
 Console.WriteLine(ex.Message); // 捕获异常时退出程序 
 } 
 } 
}

随后,我们在主程序中仅仅创建 TcpListener 类型实例,由于 RemoteClient 类在构造函数中已经完成了初始化的工作,所以我们在下 面的 while 循环中我们甚至不需要调用任何方法:

class Server { 
 static void Main(string[] args) { 
 Console.WriteLine("Server is running ... "); 
 IPAddress ip = new IPAddress(new byte[] { 127, 0, 0, 1 }); 
 TcpListener listener = new TcpListener(ip, 8500); 
 listener.Start(); // 开始侦听
 Console.WriteLine("Start Listening ..."); 
 while (true) { 
 // 获取一个连接,同步方法,在此处中断
 TcpClient client = listener.AcceptTcpClient(); 
 RemoteClient wapper = new RemoteClient(client); 
 } 
 } 
} 

好了,服务端的实现现在就完成了,接下来我们再看一下客户端的实现: 

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
张国生
下一篇:客户端的实现
评论列表

发表评论

评论内容
昵称:
关联文章

服务实现
客户实现
服务获取客户连接
2.客户服务连接
FTP服务软件 Xlight
客户发送,服务接收并输出
服务回发,客户接收并输出
详解ElasticAPM实现服务的链路追踪(NET)
1.服务对端口进行侦听
客户接收文件
客户发送数据
FTP服务软件 Serv-U
GZUpdate自动升级服务 .NET C/S Winform客户程序自动升级演示
Winform中使用HttpClient与后api服务进行交互
Winform开启一个http服务,web服务
Windows服务程序开发
windows平台的分布式微服务解决方案(5)--Web服务/WebApi的负载均衡
GZUpdate自动升级程序客户演示
mysql服务器运行环境要求
ABP VNext框架中Winform终端的开发和客户授权信息的处理