服务端实现
异步传输字符串
在上一篇中,我们由简到繁,提到了服务端的四种方式:服务一个客户端的一个请求、服务一个客户端的多个请求、服务多个客户端的 一个请求、服务多个客 户端的多个请求。我们说到可以将里层的 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开发框架网发布内容,转载请附上原文出处连接
Socket 张国生