Bidirectional Communication - Send and Receive string value correctly

Asked

Viewed 501 times

2

Follows code from server:

int port = 11000/*PortGranter.GrantPort()*/;
TcpSocketListener listener = new TcpSocketListener();
var tcs = new TaskCompletionSource<ITcpSocketClient>();

await listener.StartListeningAsync(port);
listener.ConnectionReceived += (sender, args) => tcs.SetResult(args.SocketClient);

var socket2 = await tcs.Task;
await listener.StopListeningAsync();

// for five seconds, send and receive the data 
var sentToSocket1 = new List<byte>();
var sentToSocket2 = new List<byte>();
var recvdBySocket1 = new List<byte>();
var recvdBySocket2 = new List<byte>();

// send random data and keep track of it
// also keep track of what is received
Func<ITcpSocketClient, List<byte>, List<byte>, CancellationToken, Task> sendAndReceive =
    (socket, sent, recvd, token) =>
    {
        var r = new Random(socket.GetHashCode());
        var send = Task.Run(async () =>
        {
            var buf = new byte[1000];
            while (!token.IsCancellationRequested)
            {
                //r.NextBytes(buf);
                //sent.AddRange(buf);
                //await socket.WriteStream.WriteAsync(buf, 0, buf.Length, token);
                //await socket.WriteStream.FlushAsync(token);

                Byte[] data = Encoding.UTF8.GetBytes($"Amanhã não vou para escola, porque eu estou doente.<OAF>");
                await socket.WriteStream.WriteAsync(data, 0, data.Length, token);
                await socket.WriteStream.FlushAsync(token);
            }
        });

        var recv = Task.Run(async () =>
        {
            var buf = new byte[1000];
            while (!token.IsCancellationRequested)
            {
                var len = await socket.ReadStream.ReadAsync(buf, 0, buf.Length, token);
                recvd.AddRange(buf.Take(len));
            }
        });

        var innerTcs = new TaskCompletionSource<bool>();
        token.Register(() => innerTcs.SetResult(true));

        return innerTcs.Task;
    };

Follows code from client:

int port = 11000/*PortGranter.GrantPort()*/;
TcpSocketClient socket1 = new TcpSocketClient();
await socket1.ConnectAsync("192.168.0.153", port);

var sentToSocket1 = new List<byte>();
var sentToSocket2 = new List<byte>();
var recvdBySocket1 = new List<byte>();
var recvdBySocket2 = new List<byte>();

//enviar dados aleatórios e acompanhar isso também acompanhar o que é recebido
Func<ITcpSocketClient, List<byte>, List<byte>, CancellationToken, Task> sendAndReceive =
    (socket, sent, recvd, token) =>
    {
        var r = new Random(socket.GetHashCode());
        var send = Task.Run(async () =>
        {
            var buf = new byte[1000];
            while (!token.IsCancellationRequested)
            {
                r.NextBytes(buf);
                sent.AddRange(buf);
                await socket.WriteStream.WriteAsync(buf, 0, buf.Length, token);
                await socket.WriteStream.FlushAsync(token);
            }
        });

        var recv = Task.Run(async () =>
        {
            var buf = new byte[1];
            while (!token.IsCancellationRequested)
            {
                var len = await socket.ReadStream.ReadAsync(buf, 0, buf.Length, token);
                recvd.AddRange(buf.Take(len));
            }
        });

        var innerTcs = new TaskCompletionSource<bool>();
        token.Register(() => innerTcs.SetResult(true));

        return innerTcs.Task;
    };

string result = Encoding.UTF8.GetString(recvdBySocket1.ToArray());

In the variable result returns text several times Amanhã não vou para escola, porque eu estou doente.<OAF>.

Example of how it returns:

Amanhã não vou para escola, porque eu estou doente.<OAF>Amanhã não vou para escola, porque eu estou doente.<OAF>Amanhã não vou para escola, porque eu estou doente.<OAF>Amanhã não vou para escola, porque eu estou doente.<OAF>Amanhã não vou para escola, porque eu estou doente.<OAF>...

The library I use: https://github.com/rdavisau/sockets-for-pcl

Here’s a complete code similar to mine: https://github.com/rdavisau/sockets-for-pcl/blob/dev/Sockets/Tests/Sockets.Tests/TcpSocketClientTests.cs#L166

I just want to do something like this:

Client sends value to server after server send to client and FIM.

It was the only example I found on the internet of how to do bi-directional communication using PCL (Portable Class Libraries).

Some solution ?

  • It’s not the buffer limits you’re using?

  • @Leandroangelo But the buffer would not send part by part until finish ?

  • 2

    While you do not receive the token.Iscancellationrequested you read the buffer from 0 to its size

  • 1

    Matheus I don’t know if Victor got it right. Leandro called attention to the gap with IsCancellationRequested . As long as you do not cancel the server will continue to send the message. By the way, this request is horrible...

  • @Brunocosta, if you could show a simpler example, I’d appreciate it.

  • implement a MLLP becomes much simpler

  • @Rovannlinhalis I’ve never heard of him. I’m going to do some research.

Show 2 more comments

1 answer

2


As stated in the comments by @Leandro the server will continue to write the message while there is no cancellation. I found it strange not to have a simple example as a server echo in the Github so I made mine.

Server

static async Task Run()
{
    var listenPort = 11000;
    var listener = new TcpSocketListener();
    listener.ConnectionReceived += async (sender, args) =>
    {
        var client = args.SocketClient;
        var reader = new StreamReader(client.ReadStream);
        var data = await reader.ReadLineAsync() + "\n";
        var bytes = Encoding.UTF8.GetBytes(data);
        await client.WriteStream.WriteAsync(bytes, 0, bytes.Length);
        await client.WriteStream.FlushAsync();
    };

    await listener.StartListeningAsync(listenPort);
}

Client

static async Task Run()
{
    var address = "127.0.0.1";
    var port = 11000;

    var client = new TcpSocketClient();
    await client.ConnectAsync(address, port);

    var bytes = Encoding.UTF8.GetBytes("Olá mundo\n");
    await client.WriteStream.WriteAsync(bytes, 0, bytes.Length);
    await client.WriteStream.FlushAsync();

    var reader = new StreamReader(client.ReadStream);
    var data = await reader.ReadLineAsync();
    Console.WriteLine(data);
}

In this case the client sends a message to the server, the server sends the message back. The client displays the message on the console and disconnects.

One important observation to make is that I chose to use the ReadLineAsync of StreamReader. What this means is that either the messages sent by the server or the messages sent by the client must end in \n.

I hope this is a more useful example for your objectives than you have already found.

  • Two codes that simple ? It works perfectly. I don’t know how to thank you !

  • Just one question, which is outside my question, It is possible to make the client send 1 parameter to server and server sending 3 parameters to client. Is that possible? Like, one for string, int and Datetime.

  • @Matheusmiranda Basically what to do is implement your protocol? A little more and Voce is using http. Can use SignalR? It is basically websockets with a simple to use API. There are situations where Voce uses TCP if you want to do your protocol. But if what you want to do is a apicacao, you might as well use something that exists.

  • Bruno , I do not know very well the websockets, because the idea is you take the data you have in "Winforms" and pass to "android Xamarin". I do not know if the websockets can do this.

  • Basically what you want to do is implement your protocol? Yes.

  • 1

    @Matheusmiranda. Once again, it seems that Signalr does what Oce wants. You should take a look at this over the weekend. It is widely used in professional environment so even if you will not use will always be with knowledge for the future.

  • Okay, I’ll do a little research.

  • Bruno, is it possible to communicate using the password ? I’m thinking about doing this. The server creates the random password with its single ip and client connects with ip address and password.

  • @Matheusbasic Miranda Basic wants an Article system. It is possible to do yes.

  • Bruno, in your code, sometimes I get an exception: Unable to read data from the transport Connection: Connection reset by peer. Because ?

  • @Matheusmiranda I am sorry that I did not answer your question but it seems that you have already asked another question on the subject.

Show 6 more comments

Browser other questions tagged

You are not signed in. Login or sign up in order to post.