连接到通过Ngrok暴露的TCPLISTENER时的超时

发布于 2025-02-11 08:44:01 字数 4776 浏览 2 评论 0原文

我有两个工作服务作为TCP客户端和服务器。我正在尝试将单个字节从客户端发送到服务器,并使用确认字节的服务器响应。

当两者在本地运行时,一切都起作用,但是当我通过Ngrok公开服务器时,客户端会暂停而无法连接。 NGrok诊断没有报告任何问题。

使用常规插座代替TCP包装器会导致相同的例外。

最小的复制,步骤和例外。

服务器

using Serilog;
using System.Net;
using System.Net.Sockets;

namespace TcpServer
{
    public class ServerService : BackgroundService
    {
        private readonly ILogger<ServerService> _logger;

        public ServerService(ILogger<ServerService> logger)
        {
            _logger = logger;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var acknowledgement = new byte[] { 2 };
            var receiveBuffer = new byte[1];
            TcpClient? client = null;
            NetworkStream? stream = null;

            return Task.Run(() =>
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    try
                    {
                        var server = new TcpListener(new IPAddress(new byte[] { 127, 0, 0, 1 }), 2222);
                        server.Start();
                        Log.Debug("Listening on endpoint {Endpoint}", server.LocalEndpoint);

                        client = server.AcceptTcpClient();
                        Log.Debug("Connection request accepted");

                        var stream = client.GetStream();
                        var received = stream.ReadByte();
                        Log.Information("Message {Message} received", received);

                        stream.Write(acknowledgement, 0, 1);
                        Log.Debug("Acknowledgement sent");

                        stream.Close();
                        client.Close();
                    }
                    catch (Exception ex)
                    {
                        stream?.Close();
                        client?.Close();
                        Log.Error("Exception {Exception} occurred", ex);
                    }
                   
                    stream?.Close();
                    client?.Close();
                    Log.CloseAndFlush();
                    stoppingToken = new CancellationToken(true);
                }
            }, stoppingToken);
        }
    }
}

客户端

using Serilog;
using Serilog.Core;
using System.Net;
using System.Net.Sockets;

namespace TcpClient
{
    public class ClientService : BackgroundService
    {
        private readonly ILogger<ClientService> _logger;
        private readonly IConfiguration _configuration;

        public ClientService(ILogger<ClientService> logger, IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var messageToSend = new byte[] { 1 };
            var receiveBuffer = new byte[1];
            System.Net.Sockets.TcpClient? client = null;
            NetworkStream? stream = null;

            var noTries = 5;

            return Task.Run(() =>
            {
                while (!stoppingToken.IsCancellationRequested &&
                       noTries-- > 0)
                {
                    try
                    {
                        client = new System.Net.Sockets.TcpClient("localhost", 2222);
                        Log.Debug("Connected to the remote server");

                        stream = client.GetStream();

                        stream.Write(messageToSend);
                        Log.Information("Message sent");

                        stream.Read(receiveBuffer);
                        Log.Debug("Acknowledgement received");
                        noTries = 0;
                    }
                    catch (Exception ex)
                    {
                        stream?.Close();
                        client?.Close();
                        Log.Error("Exception {Exception} occurred", ex);
                    }
                }

                stream?.Close();
                client?.Close();
                Log.CloseAndFlush();
            }, stoppingToken);
        }
    }
}

步骤

  1. 运行服务器服务。
  2. 启动NGrok并执行命令NGROK TCP 2222
  3. 将给定的主机名和端口用作客户端参数。
  4. 运行客户。

例外(重复)

[13:19:42 ERR] Exception System.Net.Internals.SocketExceptionFactory+ExtendedSocketException (10060): A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

I have two worker services acting as TCP client and server. I am trying to send a single byte from the client to server and have the server response with an acknowledgement byte.

Everything works when both are running locally, but when I expose the server via ngrok, the client gets timeouts and can't connect. ngrok diagnose doesn't report any issues.

Using regular sockets instead of TCP wrappers resulted in the same exceptions.

Minimal repro, steps and exceptions follow.

Server

using Serilog;
using System.Net;
using System.Net.Sockets;

namespace TcpServer
{
    public class ServerService : BackgroundService
    {
        private readonly ILogger<ServerService> _logger;

        public ServerService(ILogger<ServerService> logger)
        {
            _logger = logger;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var acknowledgement = new byte[] { 2 };
            var receiveBuffer = new byte[1];
            TcpClient? client = null;
            NetworkStream? stream = null;

            return Task.Run(() =>
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    try
                    {
                        var server = new TcpListener(new IPAddress(new byte[] { 127, 0, 0, 1 }), 2222);
                        server.Start();
                        Log.Debug("Listening on endpoint {Endpoint}", server.LocalEndpoint);

                        client = server.AcceptTcpClient();
                        Log.Debug("Connection request accepted");

                        var stream = client.GetStream();
                        var received = stream.ReadByte();
                        Log.Information("Message {Message} received", received);

                        stream.Write(acknowledgement, 0, 1);
                        Log.Debug("Acknowledgement sent");

                        stream.Close();
                        client.Close();
                    }
                    catch (Exception ex)
                    {
                        stream?.Close();
                        client?.Close();
                        Log.Error("Exception {Exception} occurred", ex);
                    }
                   
                    stream?.Close();
                    client?.Close();
                    Log.CloseAndFlush();
                    stoppingToken = new CancellationToken(true);
                }
            }, stoppingToken);
        }
    }
}

Client

using Serilog;
using Serilog.Core;
using System.Net;
using System.Net.Sockets;

namespace TcpClient
{
    public class ClientService : BackgroundService
    {
        private readonly ILogger<ClientService> _logger;
        private readonly IConfiguration _configuration;

        public ClientService(ILogger<ClientService> logger, IConfiguration configuration)
        {
            _logger = logger;
            _configuration = configuration;
        }

        protected override Task ExecuteAsync(CancellationToken stoppingToken)
        {
            var messageToSend = new byte[] { 1 };
            var receiveBuffer = new byte[1];
            System.Net.Sockets.TcpClient? client = null;
            NetworkStream? stream = null;

            var noTries = 5;

            return Task.Run(() =>
            {
                while (!stoppingToken.IsCancellationRequested &&
                       noTries-- > 0)
                {
                    try
                    {
                        client = new System.Net.Sockets.TcpClient("localhost", 2222);
                        Log.Debug("Connected to the remote server");

                        stream = client.GetStream();

                        stream.Write(messageToSend);
                        Log.Information("Message sent");

                        stream.Read(receiveBuffer);
                        Log.Debug("Acknowledgement received");
                        noTries = 0;
                    }
                    catch (Exception ex)
                    {
                        stream?.Close();
                        client?.Close();
                        Log.Error("Exception {Exception} occurred", ex);
                    }
                }

                stream?.Close();
                client?.Close();
                Log.CloseAndFlush();
            }, stoppingToken);
        }
    }
}

Steps

  1. Run the server service.
  2. Start ngrok and execute command ngrok tcp 2222.
  3. Hardcode the given hostname and port as client params.
  4. Run the client.

Exception (repeated)

[13:19:42 ERR] Exception System.Net.Internals.SocketExceptionFactory+ExtendedSocketException (10060): A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文