[英]C# multiuser TCP server
Trying to create an async tcp server.尝试创建异步 tcp 服务器。 Previously I could accomplish this with Begin/End pattern pretty good and handle multiple clients like this:
以前我可以用 Begin/End 模式很好地完成这个,并像这样处理多个客户端:
class Server
{
IPEndPoint ipep;
TcpListener listener;
bool Running;
List<Client> clients;
public Server(string host)
{
IPAddress ip = IPAddress.Parse(host);
ipep = new(ip, 21);
Running = false;
clients = new();
}
public void Start()
{
listener = new(ipep);
listener.Start();
Running = true;
while (Running)
listener.BeginAcceptTcpClient(Accept, null);
}
public void Accept(IAsyncResult ar)
{
Client client = new(listener.EndAcceptTcpClient(ar));
clients.Add(client);
client.WaitCommands();
}
}
class Client
{
TcpClient client;
NetworkStream stream;
public Client(TcpClient client)
{
this.client = client;
stream = client.GetStream();
}
public void WaitCommands()
{
stream.BeginRead(/*some buffer stuff*/, Receive, null);
}
public void Receive(IAsyncResult ar)
{
stream.EndRead(ar);
stream.BeginRead(/*again buffer stuff*/, Receive, null);
}
}
and there are a lot of examples of this in the Internet.互联网上有很多这样的例子。 But MSDN seems to recommend using async methods instead, so I wanna convert to it.
但是 MSDN 似乎建议使用异步方法,所以我想转换为它。 Here's what I have:
这是我所拥有的:
class Server
{
IPEndPoint ipep;
TcpListener listener;
bool Running;
List<Client> clients;
public Server(string host)
{
IPAddress ip = IPAddress.Parse(host);
ipep = new(ip, 21);
Running = false;
clients = new();
}
public async Task Start()
{
listener = new(ipep);
listener.Start();
Running = true;
while (Running)
{
Client c = await listener.AcceptTcpClientAsync();
clients.Add(c);
await c.WaitCommands();
}
}
}
class Client
{
TcpClient client;
NetworkStream stream;
public Client(TcpClient client)
{
this.client = client;
stream = client.GetStream();
}
public async Task WaitCommands()
{
while (true)
{
await stream.ReadAsync(/*buffer stuff*/);
}
}
}
and obviously await c.WaitCommands();
显然
await c.WaitCommands();
blocks other clients, since app is stuck in while (true) loop and never reaches await Accept again.阻止其他客户端,因为应用程序卡在 while (true) 循环中并且永远不会再次到达 await Accept。 I found some that
_ = Task.Run(async () => await client.WaitCommands());
我发现一些
_ = Task.Run(async () => await client.WaitCommands());
does the trick.成功了。 But as I understood that takes threads from threadpool, unlike Begin/End approach (or am I wrong? that's the question too).
但据我了解,这与 Begin/End 方法不同(或者我错了?这也是问题)。
So the questions are所以问题是
Something like this:像这样的东西:
using System.Net;
using System.Net.Sockets;
var svr = new Server("127.0.0.1");
await svr.Run();
Console.WriteLine("Goodby, World!");
class Server
{
IPEndPoint ipep;
TcpListener listener;
bool Running;
List<Client> clients;
private CancellationTokenSource cts;
public Server(string host)
{
IPAddress ip = IPAddress.Parse(host);
ipep = new(ip, 1121);
Running = false;
clients = new();
this.cts = new CancellationTokenSource();
}
public void Stop()
{
Running = false;
cts.Cancel();
}
public async Task Run()
{
listener = new(ipep);
listener.Start();
Running = true;
while (Running)
{
var c = await listener.AcceptTcpClientAsync(cts.Token);
var client = new Client(c);
clients.Add(client);
var clientTask = client.Run(); //don't await
clientTask.ContinueWith(t => clients.Remove(client));
}
}
}
class Client
{
TcpClient client;
NetworkStream stream;
public Client(TcpClient client)
{
this.client = client;
stream = client.GetStream();
}
public async Task Run()
{
var r = new StreamReader(stream);
var w = new StreamWriter(stream);
while (true)
{
await w.WriteLineAsync("You are standing in an open field west of a white house, with a boarded front door. There is a small mailbox here.");
await w.WriteAsync(">");
await w.FlushAsync();
var l = await r.ReadLineAsync();
await w.WriteLineAsync("Invalid command " + l);
}
}
}
Which you can test with你可以用它来测试
c:\> telnet localhost 1121
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.