【问题标题】:TCPClient runs into timeout after sending message to TCPListenerTCPClient 在向 TCPListener 发送消息后超时
【发布时间】:2020-09-04 22:24:30
【问题描述】:

我想创建一个监听传入消息的 .NET Core TCP 服务器。我创建了一个小类用于测试目的:

internal class TCPServer
{
    private readonly TcpListener tcpListener;

    public TCPServer()
    {
        tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 1234);
    }

    public async Task Start()
    {
        tcpListener.Start();

        while (true)
        {
            TcpClient tcpClient = await tcpListener.AcceptTcpClientAsync();
            NetworkStream networkStream = tcpClient.GetStream();
            byte[] messageBuffer = new byte[tcpClient.ReceiveBufferSize];
            int bytesRead = networkStream.Read(messageBuffer, 0, tcpClient.ReceiveBufferSize);
            string dataReceived = Encoding.ASCII.GetString(messageBuffer, 0, bytesRead);

            Console.WriteLine("Message from tcp client: " + dataReceived);
        }
    }
}

当向该侦听器发送消息时,客户端本身会超时。如您所见

我试图通过添加这一行来解决它

tcpClient.Close();

然后我得到这个错误

我怎样才能在不出错的情况下向该服务器发送消息?

【问题讨论】:

  • TCP 是健壮的,因为每条消息都会收到一个 ACK​​,并且当没有收到 ACK 时,会根据设置自动重新发送最多 3 到 5 次消息。超时表示未收到 ACK。您在 30 秒后超时,可能您每 5 秒重试 5 次,然后在 30 秒后连接关闭。
  • 看起来客户端发送消息然后在服务器收到消息之前关闭。客户端不应关闭。
  • 所以你觉得代码没问题,客户端工具不应该关闭客户端?
  • 我认为如果客户端在发送数据后立即关闭,可能会出现竞争情况。服务器可能无法获取所有数据,然后由于 TCP 进行重试而超时。

标签: c# .net-core tcplistener


【解决方案1】:

如何启动测试服务器?你有没有检查1234端口是否打开?我建议通过“telnet 127.0.0.1 1234”检查它

如果是,您可以分享客户的代码吗?

如果否,您能否分享启动服务器的代码? 我尝试通过上面的代码运行它,并且使用 telnet 工具作为客户端运行它对我来说效果很好

class Program
{
    static void Main(string[] args)
    {
        TCPServer server = new TCPServer();
        Console.WriteLine("Starting...");
        server.Start();
        Console.WriteLine("Done.");
        Console.WriteLine("Press any key to quit.");
        Console.ReadKey();
    }
}

internal class TCPServer
{
    private readonly TcpListener tcpListener;

    public TCPServer()
    {
        tcpListener = new TcpListener(IPAddress.Parse("127.0.0.1"), 1234);
    }

    public async Task Start()
    {
        tcpListener.Start();
        try
        {
            while (true)
            {
                TcpClient     tcpClient     = await tcpListener.AcceptTcpClientAsync();
                NetworkStream networkStream = tcpClient.GetStream();
                byte[]        messageBuffer = new byte[tcpClient.ReceiveBufferSize];
                int           bytesRead     = networkStream.Read(messageBuffer, 0, tcpClient.ReceiveBufferSize);
                string        dataReceived  = Encoding.ASCII.GetString(messageBuffer, 0, bytesRead);
                Console.WriteLine("Message from tcp client: " + dataReceived);
            }
        }
        finally
        {
            tcpListener.Stop();
        }
    }
}

【讨论】:

  • 这不会解决问题,您只是将问题移至Task
  • 我只是想强调这可能是 Olaf 启动服务器的方式的问题。例如,await server.Start(); 在 async static void Main 内调用会导致代码出现问题。
【解决方案2】:

问题是您在循环中处理了客户端套接字。建立客户端套接字后,您需要保持该套接字处于活动状态。

这不是正确的“服务器”代码,但它会告诉你我的意思并解决你的问题:

while (true)
{
    var tcpClient = await tcpListener.AcceptTcpClientAsync();

    while(true){
        var messageBuffer = new byte[4096];
        
        Console.WriteLine("Waiting for data...");
        int bytesRead;
        
        try
        {
            bytesRead = tcpClient.GetStream().Read(messageBuffer, 0, messageBuffer.Length);
        }catch{ break; } // disconnected
        
        var dataReceived = Encoding.ASCII.GetString(messageBuffer, 0, bytesRead);
        Console.WriteLine($"Message from tcp client ({bytesRead} bytes): {dataReceived}");
    }
}

此解决方案将使这项工作发挥作用,但您不能同时将多个客户端连接到您的服务器。为此,您需要使用 TPL,或者在最坏的情况下,为每个客户端创建一个线程。

看看BeginRead/EndRead,看看我的意思。

【讨论】:

    猜你喜欢
    • 2014-03-16
    • 1970-01-01
    • 1970-01-01
    • 2017-04-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多