TcpClient подключается, только если сервер начинает прослушивание до вызова ConnectAsyn c - PullRequest
1 голос
/ 13 марта 2020

У меня есть базовый c TCP-клиент и сервер, работающие локально на моей машине.

Если сервер уже прослушивает, когда я вызываю ConnectAsyn c (), тогда клиент подключается к серверу, нет проблем.

Если я запускаю клиент и вызываю ConnectAsyn c (), ТОГДА запускает сервер после прослушивания клиентов, он не устанавливает sh соединение. ConnectAsyn c зависает примерно на 85 секунд, прежде чем я получаю следующую ошибку: System. Net .Sockets.SocketException (0x80004005): соединение отклонено. Это несмотря на тот факт, что сервер уже начал прослушивание.

Не уверен, влияет ли это на TcpClient, но клиент работает в проекте Xamarin.

Вот мой код:

КЛИЕНТ:

public static class DataSource
{
    private static TcpClient client;
    private static NetworkStream networkStream;

    public static bool Connected => client is null ? false : client.Connected;

    public static async Task EstablishTcpConnection(string serverIP, int port)
    {
        CloseTcpConnection();

        try
        {
            client = new TcpClient();
            await client.ConnectAsync(IPAddress.Parse(serverIP), port);
            networkStream = client.GetStream();
        }
        catch (Exception ex)
        {
            Console.WriteLine($"{nameof(EstablishTcpConnection)} Error: {ex}");
        }
    }

    public static void CloseTcpConnection()
    {
        if (networkStream != null)
        {
            networkStream.Close();
            networkStream.Dispose();
            networkStream = null;
        }

        if (client != null)
        {
            client.Close();
            client.Dispose();
            client = null;
        }
    }

    public static async Task SendTcp(string toSend)
    {
        if (client is null) return;
        if (networkStream is null) return;
        if (!Connected) return;

        if (networkStream != null && networkStream.CanWrite)
        {
            byte[] bytesToSend = ASCIIEncoding.ASCII.GetBytes(toSend);
            await networkStream.WriteAsync(bytesToSend, 0, bytesToSend.Length);
        }
    }

    public static async Task TcpListener()
    {
        while (networkStream != null && networkStream.CanRead)
        {
            if (client is null) return;
            if (networkStream is null) return;
            if (!Connected) return;

            byte[] bytesToRead = new byte[client.ReceiveBufferSize];
            int bytesRead = await networkStream.ReadAsync(bytesToRead, 0, client.ReceiveBufferSize);
            string received = Encoding.ASCII.GetString(bytesToRead, 0, bytesRead);
            Console.WriteLine($"Received: {received}");
        }
    }
}

СЕРВЕР:

internal class Program
{
    private const string serverIP = "MyServerIp";
    private const int port = myPort;

    private static void Main(string[] args)
    {
        Listener();
        Console.ReadLine();
    }

    public static async Task Listener()
    {
        //---listen at the specified IP and port no.---
        TcpListener listener = new TcpListener(IPAddress.Parse(serverIP), port);
        listener.Start();
        Console.WriteLine("Listening...");

        while (true)
        {
            //---incoming client connected---
            ReceiveClient(await listener.AcceptTcpClientAsync());
        }
    }

    public static async Task ReceiveClient(TcpClient client)
    {
        if (client is null) return;
        Console.WriteLine("Client Connected");

        //---get the incoming data through a network stream---
        NetworkStream networkStream = client.GetStream();
        byte[] buffer = new byte[client.ReceiveBufferSize];

        while (client != null && client.Connected)
        {
            //---read incoming stream---
            int bytesRead = await networkStream.ReadAsync(buffer, 0, client.ReceiveBufferSize);
            if (bytesRead == 0) break;

            //---convert the data received into a string---
            string dataReceived = Encoding.ASCII.GetString(buffer, 0, bytesRead);
            Console.WriteLine("Received : " + dataReceived);

            //---write back the text to the client---
            Console.WriteLine("Sending back : " + dataReceived);
            networkStream.Write(buffer, 0, bytesRead);
        }

        client.Close();
        client.Dispose();
        Console.WriteLine("Client Disconnected");
    }
}

Ответы [ 2 ]

1 голос
/ 13 марта 2020

Конечно ConnectAsyn c () по-прежнему должен работать, даже если сервер начинает слушать после истечения времени ожидания?

Нет; это не то, что означает «тайм-аут». «Тайм-аут» не означает «повтор».

Когда вы устанавливаете sh соединение, ваше клиентское приложение обращается к серверному приложению, запущенному на сервере. «Тайм-аут» - это просто время, которое клиентское приложение будет ожидать ответа. Если серверный компьютер работает, но не имеет прослушивающего серверного приложения для этого порта, то серверный компьютер немедленно отправит ответ, указывающий, что серверное приложение не запущено. Это будет отправлено обратно в ваше клиентское приложение. Это действительный «ответ», поэтому тайм-аут не вступает в игру.

Если вы хотите повторить подключение, ожидая сервера, вам нужно будет написать эту логику c самостоятельно.

1 голос
/ 13 марта 2020

Если вы запускаете обе программы на одном компьютере, вполне вероятно, что запрос ConnectAsyn c () будет отклонен до инициализации сервера. Это происходит потому, что на входящем порте нет процесса прослушивания. Поэтому ОС отклоняет запрос на соединение.

Проверьте тип создаваемого исключения. Если это SocketException, его свойство SocketErrorCode будет проливать больше света на причину сбоя подключения.

Полный список кодов ошибок и их описания доступен на веб-сайте Microsoft по адресу https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2.

...