0

I'm trying to communicate with server, using TCP CLient. But to communicate, there are connection rules:

  1. Whenever the reader is going to start a communication, mark 1 must be placed on its output.
  2. This signal is felt by the server as a connection request indication and is only valid after 1 second of stabilization.
  3. Once the connection request is accepted, the server starts sending the ENQ signal chars. (ENQ = 05 Hexadecimal)

I think I need to use some "sleep" function for 1 second and sending 1 as mark. So I implemented the following example I had:

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();
    }
}

When I run this code, show the message: "Connected to 192.168.0.250". Now following the rules, I need to receive the ENQ (05 Hexa) signal from the server. How do I receive this signal?

João Soares
  • 49
  • 1
  • 12
  • Look in to `TcpClient.BeginConnect()`:https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.tcpclient.beginconnect?view=netcore-3.1 – Andy Aug 05 '20 at 19:26
  • Hi Andy, I tested the BeginConnect using an example. In both methods (socket and tcpclient) it showed the connected message. After connected I need to follow the rule #3. Example that I tested: https://stackoverflow.com/questions/28158892/tcpclient-beginconnect-timeout – João Soares Aug 05 '20 at 19:58

2 Answers2

0

They way you are using the Begin... and End... pattern is a little off. I am going to give you a basic example on how you can get going on this.

What you are doing here:

tcpClient = new TcpClient(ip, port);

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

is wrong. You never call a Connect... method. So, nothing is connected.

Here are typical CRUD operations on a TcpClient object:

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();
    }
}

You can call this code by doing this:

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.");
        });
    });
})

Things become somewhat easier if you don't use the Begin... and End... methods and instead use the ...Async methods, such as ConnectAsync, WriteAsync, ReadAsync, etc. methods.

This requires a knowledge of the async/await pattern, which at first is complicated, but overtime becomes one of the most useful patterns you may ever use.

Andy
  • 12,859
  • 5
  • 41
  • 56
  • Hi Andy, thank for your help. I tested your example, but it didn't connect. I just need to read, so I commented the "tcp.Write" part.. and I added "Console.Readline();" after the message "We are connected". But the message did not appear. The server what im trying to read, is a energy meter... that uses an technology named Bisync (IBM) similar to Modbus. – João Soares Aug 06 '20 at 11:26
  • @JoãoSoares -- is there a server/port I can test with? – Andy Aug 07 '20 at 00:15
  • @JoãoSoares -- I can't test just knowing the port, i need a server to connect to so i can test or see how it works. – Andy Aug 07 '20 at 01:08
  • hmm... no unfortunately.. its an energy meter, I just have LAN access. But I have the transmission details: - Speed: 9600 Baud +/- 2%; - Type: Async; - Mode: Bidirectional; - Caracter: 1 start bit, 8 bits of data, 1 stop bit; - Block size: 53 bytes; - Time betweeen blocks: 1 full second; – João Soares Aug 07 '20 at 12:19
  • I already managed to connect, using my second answer with the BeginConnect method. Now I need to read and print the server return. Searching for BeginConnect, i think I need to implement IAsyncResult. How to use IAsyncResult to get the return of BeginConnect method? – João Soares Aug 07 '20 at 12:36
0

I tested another example, which I found here on Stack. And connected successfully using TcpClient and Socket. The example is this:

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);
            }
        }
    }
}

Now I need to figure out how to read the server response. The rule #3:

  1. Once the connection request is accepted, the server starts sending the ENQ signal chars. (ENQ = 05 Hexadecimal)
João Soares
  • 49
  • 1
  • 12