我正在尝试在C#中使用一些基本的多线程。我没有找到明确的教程,因此我对我的低于标准的代码有所了解:
class Program
{
private static TcpListener listener;
private static List<TcpClient> clients;
static void Main(string[] args)
{
listener = new TcpListener(IPAddress.Any, 1337);
clients = new List<TcpClient>();
StartListening();
Console.WriteLine("Accepting clients..");
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
static async void StartListening()
{
listener.Start();
while (true)
{
clients.Add(await listener.AcceptTcpClientAsync().ConfigureAwait(false));
Console.WriteLine("Client connected!");
HandleClient(clients[clients.Count - 1], clients.Count);
}
}
static async void HandleClient(TcpClient c, int number)
{
Console.WriteLine($"Getting client #{number}'s handshake..");
var ns = c.GetStream();
var sr = new StreamReader(ns);
var handshake = sr.ReadLine();
Console.WriteLine("Client {0}'s handshake: {1}", number, handshake);
}
}
是的,所以我试图在服务器程序中实现的目标是:
1. Accepting client
2. Receiving handshake, print it to console
3. Add to the clients list
接受客户端部分有效,但程序只在HandleClient()
的第一行之后停止。我已经尝试等待荒谬的时间(1000毫秒),即便如此,它也没有收到任何东西,也没有抛出异常(即它保持连接)。我在这里做错了什么?
如果您需要,客户端代码为here!
答案 0 :(得分:2)
您的客户端代码在这里被破坏 - 您永远不会冲洗它:
var sw = new StreamWriter(ns);
Thread.Sleep(1000);
sw.WriteLine(handshake);
不需要进行Thread.Sleep
调用,但如果您希望数据实际立即发送到网络层,则应刷新StreamWriter
:
sw.Flush();
虽然(正如Stephen Cleary指出的那样)这并不意味着它必须立即发送 ,但是有理由期望它在刷新后“合理地”很快发送。
答案 1 :(得分:2)
我正在尝试在C#中使用一些基本的多线程。
我总是对开发人员感到惊讶,他们试图通过编写一个裸机TCP / IP服务器来学习并发(当他们以前从未编写过TCP / IP时)。并发和TCP / IP是两个极其困难的主题;试图同时学习它们几乎肯定会在灾难中结束。奇怪的是,这是一种常见的方法。
如果你想学习异步,我推荐我的async
intro和article on best practices(除此之外,你会学习“避免async void
”的原则。
如果您想学习TCP / IP,我推荐我的TCP/IP .NET FAQ blog series。但是,编写TCP / IP代码几乎从不必要,并且由于您可以更改客户端和服务器,我强烈建议使用SignalR。
我怀疑你确实想学习async
,而TCP / IP正在阻碍。因此,删除较难的主题(TCP / IP)并使用async
通过更简单的通信,如WebAPI或SignalR。
(就你看到的实际问题而言,它确实是由缓冲引起的,但重要的是要注意,刷新缓冲区不会导致数据立即通过网络发送;它只会被发送到网络< em> layer 立即。正确的解决方案需要消息框架。)
答案 2 :(得分:1)
正如Jon Skeet所提到的,为了确保内容不只是放在缓冲区中,你应该冲洗它。
您的客户应该如此:
var sw = new StreamWriter(ns);
Thread.Sleep(1000); // let the server catch up
sw.WriteLine(handshake);
sw.Flush();
Console.WriteLine("Staying connected.. Press ESCAPE to exit.");
编辑:忘记提及...... Thread.Sleep(1000);
那里......你可以安全地删除它。