C# Asyn c Подключение TcpClient - PullRequest
0 голосов
/ 05 августа 2020

Я пытаюсь связаться с сервером, используя TCP CLient. Но для связи существуют правила подключения:

  1. Каждый раз, когда считыватель собирается начать обмен данными, на его выходе должна быть поставлена ​​отметка 1.
  2. Этот сигнал ощущается сервером как индикация запроса на соединение и действительна только после 1 секунды стабилизации.
  3. Как только запрос на соединение принят, сервер начинает посылать символы сигнала ENQ. (ENQ = 05 Hexadecimal)

Я думаю, мне нужно использовать некоторую функцию «сна» на 1 секунду и посылать 1 как отметку. Итак, я реализовал следующий у меня пример:

public void Initialize(string ip, int port)
{
    try
    {
        tcpClient = new TcpClient(ip, port);

        if (tcpClient.Connected)
            Console.WriteLine("Connected to: {0}:{1}", ip, port);
    }
    catch (Exception ex)
    {
        Console.WriteLine(ex.Message);
        Initialize(ip, port);
    }
}

public void BeginRead()
{
    var buffer = new byte[4096];
    NetworkStream ns = tcpClient.GetStream();
    
    ns.ReadTimeout = 1000;
    ns.BeginRead(buffer, 0, 9, EndRead, buffer);                
}

class Program
{
    static void Main(string[] args)
    {
        var client = new Client();
        client.Initialize("192.168.0.250", 2180);

        client.BeginRead();     
        Console.ReadLine();
    }
}

Когда я запускаю этот код, я показываю сообщение: «Подключено к 192.168.0.250». Теперь, следуя правилам, мне нужно получить от сервера сигнал ENQ (05 Hexa). Как мне получить этот сигнал?

Ответы [ 2 ]

0 голосов
/ 06 августа 2020

Я протестировал другой пример, который нашел здесь, в стеке. И успешно подключился с помощью TcpClient и Socket. Пример такой:

namespace test3
{
    class Program
    {
        private static void _TestSOCode()
        {
            using (var tcp = new TcpClient())
            {
                var c = tcp.BeginConnect(IPAddress.Parse("192.168.0.250"), 2180, null, null);
                var success = c.AsyncWaitHandle.WaitOne(TimeSpan.FromSeconds(1));

                if (!success)
                {
                    Console.WriteLine("Before cleanup");
                    tcp.Close();
                    tcp.EndConnect(c);
                    Console.WriteLine("After cleanup");
                    throw new Exception("Failed to connect.");
                }
            }
        }

        private static void _TestWithTcpClient()
        {
            TcpClient client = new TcpClient();
            object o = new object();

            Console.WriteLine("connecting TcpClient...");
            client.BeginConnect("192.168.0.250", 2180, asyncResult =>
            {
                Console.WriteLine("connect completed");

                try
                {
                    client.EndConnect(asyncResult);
                    Console.WriteLine("client connected");
                }
                catch (NullReferenceException)
                {
                    Console.WriteLine("client closed before connected: NullReferenceException");
                }
                catch (ObjectDisposedException)
                {
                    Console.WriteLine("client closed before connected: ObjectDisposedException");
                }

                lock (o) Monitor.Pulse(o);
            }, null);

            Thread.Sleep(1000);

            Stopwatch sw = Stopwatch.StartNew();
            client.Close();

            lock (o) Monitor.Wait(o);
            Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
            Console.WriteLine();
        }

        private static void _TestWithSocket()
        {
            Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);
            object o = new object();

            Console.WriteLine("connecting Socket...");
            socket.BeginConnect("192.168.0.250", 2180, asyncResult =>
            {
                Console.WriteLine("connect completed");

                try
                {
                    socket.EndConnect(asyncResult);
                    Console.WriteLine("socket connected");
                }
                catch (ObjectDisposedException)
                {
                    Console.WriteLine("socket closed before connected");
                }

                lock (o) Monitor.Pulse(o);
            }, null);

            Thread.Sleep(1000);

            Stopwatch sw = Stopwatch.StartNew();
            socket.Close();

            lock (o) Monitor.Wait(o);
            Console.WriteLine("close took {0:0.00} seconds", sw.Elapsed.TotalSeconds);
            Console.WriteLine();
        }

        static void Main(string[] args)
        {
            _TestWithSocket();
            _TestWithTcpClient();

            try
            {
                _TestSOCode();
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception: " + e);
            }
        }
    }
}

Теперь мне нужно выяснить, как читать ответ сервера. Правило # 3:

Как только запрос на соединение принят, сервер начинает посылать символы сигнала ENQ. (ENQ = 05 шестнадцатеричный)
0 голосов
/ 06 августа 2020

Они, как вы используете паттерн Begin... и End..., немного не так. Я собираюсь дать вам базовый c пример того, как вы можете это сделать.

Что вы здесь делаете:

tcpClient = new TcpClient(ip, port);

if (tcpClient.Connected)
    Console.WriteLine("Connected to: {0}:{1}", ip, port);

неправильно. Вы никогда не вызываете метод Connect.... Итак, ничего не подключено.

Вот типичные операции CRUD с объектом TcpClient:

public sealed class TcpClientTest
{
    private readonly TcpClient _tcpClient = new TcpClient();

    public void Connect(string host, int port, Action endConnect)
    {
        _tcpClient.BeginConnect(host, port, asyncResult =>
        {
            _tcpClient.EndConnect(asyncResult);
            endConnect?.Invoke();
        }, null);
    }

    public void Read(byte[] buffer, Action<byte[], int> endRead)
    {
        _tcpClient.GetStream().BeginRead(buffer, 0, buffer.Length, asyncResult =>
        {
            var bytesRead = _tcpClient.GetStream().EndRead(asyncResult);
            endRead?.Invoke(buffer, bytesRead);
        }, null);
    }

    public void Write(byte[] buffer, Action endWrite)
    {
        _tcpClient.GetStream().BeginWrite(buffer, 0, buffer.Length, asyncRsult =>
        {
            _tcpClient.GetStream().EndWrite(asyncRsult);
            endWrite?.Invoke();
        }, null);
    }

    public void Disconnect()
    {
        _tcpClient.Close();
    }
}

Вы можете вызвать этот код следующим образом:

Console.WriteLine("Connecting...");
var tcp = new TcpClientTest();
tcp.Connect("www.example.com", 80, () =>
{
    Console.WriteLine("We are connected... Sending request...");
    var str = "GET / HTTP/1.1\r\nHost: www.example.com\r\n\r\n";
    tcp.Write(Encoding.UTF8.GetBytes(str), () =>
    {
        Console.WriteLine("Data sent. Waiting for data to come back...");
        var bytes = new byte[2048];
        tcp.Read(bytes, (buffer, read) =>
        {
            var data = Encoding.UTF8.GetString(buffer, 0, read);
            Console.WriteLine($"Data Read: {data}");

            Console.WriteLine("Closing connection");
            tcp.Disconnect();

            Console.WriteLine("Done.");
        });
    });
})

Все станет немного проще, если вы не будете использовать методы Begin... и End..., а вместо этого будете использовать методы ...Async, такие как ConnectAsync, WriteAsync, ReadAsync, et c.

Для этого требуется знание паттерна async / await, который сначала является сложным, но со временем становится одним из самых полезных паттернов, которые вы можете когда-либо использовать.

...