TCP socket concurrency
TCP socket concurrency
Dear,
I have a background worker in C# code which interacts with ProppFrexx with the TCP client.
Sometimes, I send a command en retrieve the data, but I get input from another command.
Is there something possible to combat this?
Hereby my proof of concept code;
I have a background worker in C# code which interacts with ProppFrexx with the TCP client.
Sometimes, I send a command en retrieve the data, but I get input from another command.
Is there something possible to combat this?
Hereby my proof of concept code;
Code: Select all
using System.Net;
using System.Net.Sockets;
using System.Text;
var serverIp = "192.168.1.112"; // Replace with your server's IP address
var serverPort = 8052; // Replace with your server's port number
var serverEndPoint = new IPEndPoint(IPAddress.Parse(serverIp), serverPort);
using var client = new TcpClient();
client.Connect(serverEndPoint);
void SendTCP(string msg)
{
var message = $"{msg}\r\n\r\n";
var data = Encoding.ASCII.GetBytes(message);
client.GetStream().Write(data, 0, data.Length);
}
string Receive()
{
byte[] buffer = new byte[1024];
int bytesRead = client.GetStream().Read(buffer, 0, buffer.Length);
string response = Encoding.ASCII.GetString(buffer, 0, bytesRead);
// Console.WriteLine("Server response: {0}", response);
return response;
}
void GetEntries()
{
while (true)
{
SendTCP("AUTHORIZATION password");
Receive();
SendTCP("PLS_CURRENT_GET_ENTRIES");
Receive();
}
}
void GetName()
{
while (true)
{
SendTCP("AUTHORIZATION password");
Receive();
SendTCP("PLS_CURRENT_NAME_GET");
var data = Receive();
Console.WriteLine($"current name: {data}");
}
}
// Create two threads
Thread thread1 = new Thread(new ThreadStart(GetEntries));
Thread thread2 = new Thread(new ThreadStart(GetName));
// Start the threads
thread1.Start();
thread2.Start();
// Wait for the threads to finish
thread1.Join();
thread2.Join();
// Close the connection
client.Close();
Last edited by Thijmen on 04 May 2023 19:09, edited 1 time in total.
Re: TCP socket concurrency
I guess there is some max length of the socket (Is it 1448 perhaps?
). I need to do some while loop to fetch resuming data in the socket before I send a new command. PLS_CURRENT_GET_ENTRIES returns more than my buffer length (even if I do 1024 * 10 as buffer length, PF sends 1448 string length back).
Do you have any suggestions how I can combat my issue?
The code below doesnt work, because at some point the content.Length > 0 but it is also the last batch of data.
So question is: what is the last character of a socket response or what is the max length of it?
Even if there is such character, "\n" perhaps, is it 100% sure that it is at the end and not splitted in 2 batches?

Do you have any suggestions how I can combat my issue?
The code below doesnt work, because at some point the content.Length > 0 but it is also the last batch of data.
Code: Select all
void GetName()
{
while (true)
{
SendTCP(client2, "AUTHORIZATION password");
Receive(client2);
SendTCP(client2, "PLS_CURRENT_GET_ENTRIES");
var content = Receive(client2);
while (content.Length > 1024)
{
content = Receive(client2);
}
SendTCP(client2, "PLS_CURRENT_NAME_GET");
var data = Receive(client2);
Console.WriteLine($"current name: {data}");
}
}
Even if there is such character, "\n" perhaps, is it 100% sure that it is at the end and not splitted in 2 batches?
Re: TCP socket concurrency
I am sorry, but these are C# coding questions - which I can not answer here in this forum 
So you'll still receive an example code here, but in general I do not answer C# coding questions here - these should be addressed to other forums...
There is no defined length of the reply, you basically loop until you receive all bytes.
Note, the reply also ends with a double CRLF.
Here is an example to read commands from a file and send them all one by one and receive the replies...

So you'll still receive an example code here, but in general I do not answer C# coding questions here - these should be addressed to other forums...
Code: Select all
using System;
using System.Threading;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace ProppFrexx.RemoteControl
{
/// <summary>
/// Represents a TCP remote control client which is able to send commands and receive replies to and from a remote control server.
/// </summary>
/// <remarks>The client remote controls the server.</remarks>
public class RemoteControlClient : IDisposable
{
#region IDisposable Members
public void Dispose()
{
Disconnect();
}
#endregion
private TcpClient _tcpClient = null;
private NetworkStream _tcpStream = null;
private Timer _pingTimer = null;
private TimerCallback _timerDelegate;
/// <summary>
/// Creates a new instance of a TCP remote control client.
/// </summary>
public RemoteControlClient()
{
// Create the delegate that invokes methods for the timer.
_timerDelegate = new TimerCallback(Ping);
}
/// <summary>
/// Gets a value indicating, if the client is connected to a server.
/// </summary>
public bool IsConnected
{
get { return _tcpClient != null && _tcpClient.Connected; }
}
/// <summary>
/// Connects the client to the TCP remote control server.
/// </summary>
/// <param name="host">The DNS of the remote control server to which you intend to connect.</param>
/// <param name="port">The port number of the remote control server to which you intend to connect.</param>
/// <param name="password">The authorization password of the TCP remote control server.</param>
/// <returns>TRUE on success - else FALSE.</returns>
public bool Connect(string host, int port, string password)
{
_tcpClient = new TcpClient(host, port);
_tcpClient.NoDelay = true;
_tcpClient.LingerState = new LingerOption(false, 0);
_tcpClient.ReceiveTimeout = 5000;
_tcpClient.SendTimeout = 5000;
if (_tcpClient.Connected)
{
// get the network stream
_tcpStream = _tcpClient.GetStream();
// send authorization
string reply = Send("AUTHORIZATION " + password + Environment.NewLine + Environment.NewLine);
if (reply.StartsWith("OK" + Environment.NewLine))
{
// start the ping timer
_pingTimer = new Timer(_timerDelegate, null, 5000, 5000);
return true;
}
else
{
Disconnect();
throw new Exception("Remote Authorization failed!");
}
}
return false;
}
/// <summary>
/// Disconnects the client from the TCP remote control server.
/// </summary>
/// <returns></returns>
public bool Disconnect()
{
if (_pingTimer != null)
{
_pingTimer.Change(Timeout.Infinite, Timeout.Infinite);
_pingTimer.Dispose();
_pingTimer = null;
}
if (_tcpStream != null)
{
_tcpStream.Close();
_tcpStream.Dispose();
_tcpStream = null;
}
if (_tcpClient != null)
{
_tcpClient.Close();
_tcpClient = null;
}
return true;
}
/// <summary>
/// Sends the TCP remote control message to a server.
/// </summary>
/// <param name="tcpMessage">The message resp. command to send.</param>
/// <returns>The servers reply message on success - else an exception will be thrown.</returns>
/// <remarks>
/// Note: This command blocks
/// </remarks>
public string Send(string tcpMessage)
{
if (!IsConnected || _tcpStream == null)
{
throw new Exception("Not connected to the TCP remote control server.");
}
// the tcp message (must be terminated with a double CRLF)
if (!tcpMessage.EndsWith(Environment.NewLine + Environment.NewLine))
{
if (!tcpMessage.EndsWith(Environment.NewLine))
tcpMessage += Environment.NewLine + Environment.NewLine;
else
tcpMessage += Environment.NewLine;
}
string reply = String.Empty;
lock (this)
{
byte[] bufferSend = Encoding.UTF8.GetBytes(tcpMessage);
_tcpStream.Write(bufferSend, 0, bufferSend.Length);
if (!tcpMessage.StartsWith("BYE"))
{
// Read the reply (must also end with a double CRLF)
byte[] bufferRead = new byte[_tcpClient.ReceiveBufferSize];
int len;
DateTime _timeout = DateTime.Now;
do
{
// Read can return anything from 0 to numBytesToRead.
// This method blocks until at least one byte is read.
len = _tcpStream.Read(bufferRead, 0, _tcpClient.Available);
if (len > 0)
reply += Encoding.UTF8.GetString(bufferRead, 0, len);
else if ((int)(DateTime.Now - _timeout).TotalMilliseconds > _tcpStream.ReadTimeout)
break;
}
while (!reply.EndsWith(Environment.NewLine + Environment.NewLine));
}
}
return reply;
}
private void Ping(object stateInfo)
{
try
{
Send("PING" + Environment.NewLine + Environment.NewLine);
}
catch
{
Disconnect();
}
}
}
}
Note, the reply also ends with a double CRLF.
Here is an example to read commands from a file and send them all one by one and receive the replies...
Code: Select all
private static bool ProcessCommandFile(string host, int port, string password, string fileName)
{
bool ok = true;
try
{
string[] commands = File.ReadAllLines(fileName);
if (commands != null)
{
using (RemoteControl.RemoteControlClient remoteClient = new RemoteControl.RemoteControlClient())
{
ok = remoteClient.Connect(host, port, password);
if (ok)
{
foreach (string command in commands)
{
if (String.IsNullOrEmpty(command))
continue;
Console.WriteLine("Processing Command: {0}", command);
string result = remoteClient.Send(command);
Console.WriteLine(result.TrimEnd());
if (result.StartsWith("ERROR")
ok = false;
}
remoteClient.Send("BYE");
remoteClient.Disconnect();
}
else
{
Console.WriteLine("Connect to server '{0}:{1}' failed!", host, port);
}
}
}
}
catch (Exception ex)
{
Console.WriteLine("ERROR: {0}", ex.Message);
ok = false;
}
return ok;
}
Bernd - radio42
ProppFrexx ONAIR - The Playout and Broadcast Automation Solution
ProppFrexx ONAIR - The Playout and Broadcast Automation Solution
Re: TCP socket concurrency
Awesome, I only had to check for the double line endings. Thank you so much!