StreamWriter ReadLine方法挂起程序

时间:2016-05-23 17:22:01

标签: c# asynchronous streamwriter

我正在尝试在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

3 个答案:

答案 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 introarticle 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);那里......你可以安全地删除它。