110,535
社区成员
发帖
与我相关
我的任务
分享
server= new TcpListener(new IPEndPoint(IPAddress.Any, port);
server.Start();
server.BeginAcceptTcpClient(ClientConnected, null);
class Session
{
public TcpClient Client; //客户端连接
public byte[] Buffer; //异步读数据的缓冲区
public MemoryStream Cache; //读取到消息结束标志之前累计读取到的字节
}
private void ClientConnected(IAsyncResult handler)
{
var client = this.EndAcceptTcpClient(handler);
var buffer = new byte[40960];
var session = new Session { Client = client, Buffer = buffer, Cache = new MemoryStream() };
client.GetStream().BeginRead(buffer, 0, buffer.Length, Process, session);
this.BeginAcceptTcpClient(ClientConnected, null);
}
当一个客户端会话连接,我们要做两件式,开始异步读这个会话数据,以及继续监听其它会话。其中,当开始异步读的时候,要把当前会话信息作为参数(最后一个参数)传递给处理读到消息的方法Process。这样,读取当前会话消息是异步的,处理其它客户端连接也是异步的。private void Process(IAsyncResult handler)
{
var session = (Session)handler.AsyncState;
int len = 0;
len = session.Client.GetStream().EndRead(handler);
if (len > 0)
{
session.Cache.Write(session.Buffer, 0, len);
var c = session.Buffer[len - 1];
if (c == 13 || c == 10)
{
session.Cache.Position = 0;
var rs = new StreamReader(session.Cache, Encoding.UTF8);
while (!rs.EndOfStream)
{
var ln = rs.ReadLine().Trim();
ProcessCommand(ln, session.Client);
}
session.Cache = new MemoryStream(); //如果是短连接,这里直接写 return; 代码
}
}
session.Client.GetStream().BeginRead(session.Buffer, 0, session.Buffer.Length, Process, handler.AsyncState);
}
仅当buffer中读取的最后一个字符恰好是回车或者换行时,我们才循环从整个消息缓冲区中逐一取出消息(注意由于读取到的数据可能是“沾包”的,因此可能有不只一条消息)并调用ProcessCommand方法来解析和处理消息。如果处理完所有消息,则会把整个接收缓冲区重新清空。如果处理完所有消息之后还要长连接,或者buffer的最后一个字符不是消息结束符号,我们继续异步读取下一个buffer。