.net c# zeromq request reply simultaneously - c#

I am relatively new to ZeroMq.
What i want to do is send requests and receive replies at the same time.
I read a lot of examples and the ZeroMq guide but i dont know how to achieve this.
Currently my code looks this way:
public void SendRequestAsync<T>(T request)
{
Task.Factory.StartNew(() =>
{
using (ZmqSocket socket = _context.CreateSocket(SocketType.REQ))
{
string endPoint = string.Format("tcp://{0}:{1}", ServiceIpAddress, Port);
socket.Connect(endPoint);
var serializer = new XmlSerializer(request.GetType());
using (var byteStream = new MemoryStream())
{
serializer.Serialize(byteStream, request);
socket.Send(byteStream.ToArray());
}
}
});
if (!_isListening)
{
StartListeningForReplies();
}
}
private void StartListeningForReplies()
{
_responseThread = new Thread(ReplyThreadStart);
_responseThread.Start();
_isListening = true;
}
private void ReplyThreadStart()
{
using (var replySocket = _context.CreateSocket(SocketType.REQ))
{
string endPoint = string.Format("tcp://*:{0}", Port);
replySocket.Bind(endPoint);
while (!_listeningAborted)
{
byte[] buffer = new byte[1024];
replySocket.Receive(buffer);
// put into queue for processing
}
}
}
I have created a single context before and use this context to create the sockets.
Do i need to use different ports for sending and receiving, and yet another port for publishing?
Please help.

Related

UdpClient stops sending messages after second client joins

I have some code for a server and client, with the server potentially having multiple clients. When it is one client and one server, I am sending and receiving messages perfectly. However, when a second user joins, the clients no longer receive the messages.
Here's how I'm sending the messages serverside:
if (Clients.Count == 0)
return;
foreach (ConnectedClient client in Clients)
{
BinaryFormatter messageFormatter = new BinaryFormatter();
try
{
using (var ms = new MemoryStream())
{
messageFormatter.Serialize(ms, new Message() { Content = new GameData(Clients), MessageType = EServerCommand.GameUpdate, origin = (IPEndPoint)Client.Client.LocalEndPoint });
Client.Send(ms.ToArray(), ms.ToArray().Length, new IPEndPoint(client.ConnectionPlayer.ClientIP, 42070));
}
}
catch (Exception e)
{
return;
}
}
Clientside, I am receiving the messages like so:
public async void HandleServerMessages()
{
while(true)
{
var message = await Receive();
if (message.MessageType == EServerCommand.GameUpdate)
{
GameUpdateEvent((GameData)message.Content);
}
}
}
public override async Task<Message> Receive()
{
var result = await Client.ReceiveAsync();
using (var memStream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
memStream.Write(result.Buffer, 0, result.Buffer.Length);
memStream.Seek(0, SeekOrigin.Begin);
var message = formatter.Deserialize(memStream);
return (Message)message;
}
}
Like I mentioned earlier, a single client and server works as expected, the problems only arise when a second client connects.
EDIT: I have since tried using wireshark, it seems the client computer is receiving the packets, but the client code is not registering this as a "receive". Here's what wireshark is showing (10.0.0.157 is the computer, 10.0.0.170 is the server.

JSONRpc Client over websocket C#

I need a JSON-Rpc client to communicate over websocket to the server. In particular, I need to create an interface and use methods to send JSON requests to the server.
Does someone know how to do that?
I found the StreamJsonRpc library, but it works over stream and not over websocket.
Can I get the stream from websocket connection and pas it to StreamJsonRpc?
Do you have other ideas?
You only need Json.net and WebSocket4Net.
You can see there.
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Security.Authentication;
using WebSocket4Net;
namespace LightStreamSample
{
class WebSocket4NetSample
{
static void Main(string[] args)
{
var channelName = "[your websocket server channel name]";
// note: reconnection handling needed.
var websocket = new WebSocket("wss://[your web socket server websocket url]", sslProtocols: SslProtocols.Tls12);
websocket.Opened += (sender, e) =>
{
websocket.Send(
JsonConvert.SerializeObject(
new
{
method = "subscribe",
#params = new { channel = channelName },
id = 123,
}
)
);
};
websocket.MessageReceived += (sender, e) =>
{
dynamic data = JObject.Parse(e.Message);
if (data.id == 123)
{
Console.WriteLine("subscribed!");
}
if (data.#params != null)
{
Console.WriteLine(data.#params.channel + " " + data.#params.message);
}
};
websocket.Open();
Console.ReadKey();
}
}
}
To update this post, it is now possible to pass the stream from the websocket using StreamJsonRpc.
Github websocket sample for .NetCore
using (var jsonRpc = new JsonRpc(new WebSocketMessageHandler(socket)))
{
try
{
jsonRpc.AddLocalRpcMethod("Tick", new Action<int>(tick => Console.WriteLine($"Tick {tick}!")));
jsonRpc.StartListening();
Console.WriteLine("JSON-RPC protocol over web socket established.");
int result = await jsonRpc.InvokeWithCancellationAsync<int>("Add", new object[] { 1, 2 }, cancellationToken);
Console.WriteLine($"JSON-RPC server says 1 + 2 = {result}");
// Request notifications from the server.
await jsonRpc.NotifyAsync("SendTicksAsync");
await jsonRpc.Completion.WithCancellation(cancellationToken);
}
catch (OperationCanceledException)
{
// Closing is initiated by Ctrl+C on the client.
// Close the web socket gracefully -- before JsonRpc is disposed to avoid the socket going into an aborted state.
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, "Client closing", CancellationToken.None);
throw;
}
}
The .Net Framework implemenation is similar but slightly different

Wait for incoming tcp/ip server request

I'm building a TCP/IP connection for my application with a warehouse system. The communication goes like this.
I send a message to the TCP/IP(Socket) server of the warehouse system.
The warehouse system responds with a message the my local TCP/IP server.
So there are no direct response messages. Instead each application as it's own server.
Yet I want my application to wait for the response coming from the other server.
So basicly I have the following code.
public string ControllerFunction() {
startLocalTcpIpServer();
sendMessage("a message");
return clientMessage;
}
This is my own server started with the start() function
public void Start() {
// Start TcpServer background thread
tcpListenerThread = new Thread(new ThreadStart(ListenForIncommingRequests)) {
IsBackground = true
};
tcpListenerThread.Start();
}
private void ListenForIncommingRequests() {
try {
tcpListener = new TcpListener(IPAddress.Parse(serverIp), port);
tcpListener.Start();
byte[] bytes = new byte[1024];
Console.WriteLine("Server Started");
while(true) {
// Get a stream object for reading
using(NetworkStream stream = tcpListener.AcceptTcpClient().GetStream()) {
int length;
// Read incomming stream into byte arrary.
while((length = stream.Read(bytes, 0, bytes.Length)) != 0) {
byte[] incommingData = new byte[length];
Array.Copy(bytes, 0, incommingData, 0, length);
// Convert byte array to string message.
string clientMessage = Encoding.ASCII.GetString(incommingData);
}
}
}
}
catch(SocketException socketException) {
Console.WriteLine("SocketException " + socketException.ToString());
}
}
So I want to use the result string clientMessage again as a return for my ControllerFunction. But how do I get the data there in a proper way?
So what you need is to be able to wait for response coming from another place in your application (local server). Response will be fired there first. Local server should have an event you can subscribe to (OnMessage in my example). This event will forward result message to you.
Synchronization can be handled using TaskCompletionSource. You will create Task that you can use to obtain result synchronously or asynchronously.
Something like this:
public string ControllerFunction()
{
return ControllerFunctionTask().Result;
}
public Task<string> ControllerFunctionTask()
{
sendMessage("a message");
var task = new TaskCompletionSource<string>();
localServer.OnMessage = (message) =>
{
task.SetResult(message);
};
return task.Task;
}
As stated in comments, synchronous waiting for asynchronous Task may lead to deadlocks. This may happen when caller thread is context thread (UI, ASP). Therefore this should be better approach:
public async Task<string> ControllerFunction()
{
return await ControllerFunctionTask();
}
public Task<string> ControllerFunctionTask()
{
sendMessage("a message");
var task = new TaskCompletionSource<string>();
localServer.OnMessage = (message) =>
{
task.SetResult(message);
};
return task.Task;
}
OnMessage can be defined this way:
public event Action<string> OnMessage;
Then it will be called right after line where you get clientMessage string:
string clientMessage = Encoding.ASCII.GetString(incommingData);
if (OnMessage != null)
OnMessage(clientMessage);

C# encapsulation when getting updates from asynchronous method

I have a tcp connection I want to keep open in the HandleConnectionAsync method of the server class. It will be receiving continuous updates from a client.
private async void HandleConnectionAsync(TcpClient tcpClient)
{
Console.WriteLine("Got connection request from {0}", tcpClient.Client.RemoteEndPoint.ToString());
try
{
using (var networkStream = tcpClient.GetStream())
using (var reader = new StreamReader(networkStream))
using (var writer = new StreamWriter(networkStream))
{
writer.AutoFlush = true;
while (true)
{
string dataFromClient = await reader.ReadLineAsync();
Console.WriteLine(dataFromClient);
await writer.WriteLineAsync("FromServer-" + dataFromClient);
}
}
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
}
I want to be able to receive the updates the reader puts into dataFromClient without having to put my code in the midst of my server implementation class.
So:
static void Main(string[] args)
{
Server s = new Server();
s.start();
//get dataFromClient as it comes in here
}
Problem is I'm not sure how to do this. Some kind of callback or event?
There are many many ways.
The least code is to pass an Action to your server eg:
Server s = new Server();
s.start(dataFromClient =>
{
// do something with data from client
});
And in HandleConnectionAsync call the action eg:
private async void HandleConnectionAsync(TcpClient tcpClient, Action<string> callback)
{
..
// Console.WriteLine(dataFromClient);
callback(dataFromClient);
..
However this does not address a few things e.g. many clients at the same time and needing to know which client is which.

Issues with getting a raspberry pi to communicate to PC with windows IOT

I have been having a horrible problem with trying to get this socket on the raspberry pi to correctly communicate to the PC socket. It is a TCP client-to-server setup. Both are running .net C# applications to do the communication. The main issue is not the connection, but when I send info from the raspberry pi to the computer, the computer only gets the info when I shutdown the raspberry... I believe it has to do with caching, but how would I fix this? Just a fair warning I am not well verse with sockets.
the Raspberry Pi Client Code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Net.Sockets;
using Windows.UI.ViewManagement;
using System.Net.Sockets;
using Windows.Web.Http;
using Windows.Devices.Gpio;
using Windows.Networking;
using Windows.Networking.Sockets;
using Windows.Storage.Streams;
using System.Threading;
using System.Runtime.InteropServices;
namespace raspberrypipad
{
class TCPclient_Client
{
private string _ip;
private int _port;
private Socket _socket;
private DataWriter _writer;
private DataReader _reader;
public delegate void Error(string message);
public event Error OnError;
public delegate void DataRecived(string data);
public event DataRecived OnDataRecived;
public string Ip
{
get { return _ip; }
set { _ip = value; }
}
public int Port
{
get { return _port; }
set { _port = value; }
}
private static ManualResetEvent _clientDone = new ManualResetEvent(false);
const int TIMEOUT_MILLISECONDS = 1000;
public async void Connect(string devicename, string pin_number, string get_portNumber, string current_ip)
{
try
{
if (Port == 0)
{
_port = 4444;
}
string result = string.Empty;
DnsEndPoint hostEntry = new DnsEndPoint(Ip, Port);
var hostName = new HostName(Ip);
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.RemoteEndPoint = hostEntry;
// Inline event handler for the Completed event.
// Note: This event handler was implemented inline in order to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
{
// Retrieve the result of this request
result = e.SocketError.ToString();
// Signal that the request is complete, unblocking the UI thread
_clientDone.Set();
});
_clientDone.Reset();
// Make an asynchronous Connect request over the socket
_socket.ConnectAsync(socketEventArg);
_socket.AcceptAsync(socketEventArg);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
_socket.NoDelay = true;
}
catch (Exception ex)
{
//ignore
}
}
public string Send(string data)
{
string response = "Operation Timeout";
// We are re-using the _socket object initialized in the Connect method
if (_socket != null)
{
// Create SocketAsyncEventArgs context object
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
// Set properties on context object
socketEventArg.RemoteEndPoint = _socket.RemoteEndPoint;
socketEventArg.UserToken = null;
// Inline event handler for the Completed event.
// Note: This event handler was implemented inline in order
// to make this method self-contained.
socketEventArg.Completed += new EventHandler<SocketAsyncEventArgs>(delegate (object s, SocketAsyncEventArgs e)
{
response = e.SocketError.ToString();
e.Dispose();
// Unblock the UI thread
_clientDone.Set();
});
// Add the data to be sent into the buffer
byte[] payload = Encoding.UTF8.GetBytes(data);
socketEventArg.SetBuffer(payload, 0, payload.Length);
// Sets the state of the event to nonsignaled, causing threads to block
_clientDone.Reset();
// Make an asynchronous Send request over the socket
_socket.SendBufferSize = payload.Length;
_socket.SendToAsync(socketEventArg);
// _socket.Shutdown(SocketShutdown.Send);
// Block the UI thread for a maximum of TIMEOUT_MILLISECONDS milliseconds.
// If no response comes back within this time then proceed
_clientDone.WaitOne(TIMEOUT_MILLISECONDS);
}
else
{
response = "Socket is not initialized";
}
return response;
}
public void close()
{
_socket.Dispose();
}
}
}
The server code for the computer is a little confusing, I know it works because other programs could send data to it in other languages... here is the code:
public TcpServerCode(int port)
{
_server = new TcpListener(IPAddress.Any, port);
_server.Start();
_isRunning = true;
if (!Directory.Exists(Environment.CurrentDirectory + "\\serverCOM"))
Directory.CreateDirectory(Environment.CurrentDirectory + "\\serverCOM");
var th = new Thread(LoopClients);
th.Start();
}
public void LoopClients()
{
while (_isRunning)
try
{
// wait for client connection
var newClient = _server.AcceptTcpClient();
// client found.
// create a thread to handle communication
var t = new Thread(HandleClient);
var ch = new clientHolder();
ch.generateRandomName();
ch._tcp = newClient;
clientHolderList.Add(ch);
t.Start(ch);
}
catch (Exception i)
{
Log.handleException(i);
}
}
public void HandleClient(object obj)
{
// retrieve client from parameter passed to thread
var client = (clientHolder) obj;
// sets two streams
//StreamWriter sWriter = new StreamWriter(client._tcp.GetStream(), Encoding.ASCII);
var ns = client._tcp.GetStream();
client._tcp.GetStream().ReadTimeout = 100;
var sReader = new StreamReader(client._tcp.GetStream(), Encoding.ASCII);
// you could use the NetworkStream to read and write,
// but there is no forcing flush, even when requested
var bClientConnected = true;
string sData = null;
Task getter = null;
Task sender = null;
while (bClientConnected)
if (getter != null)
{
if (getter.IsCompleted)
getter = _get(sReader, client.clientName);
}
else
{
getter = _get(sReader, client.clientName);
}
}
private static async Task _get(StreamReader reader, string clientName)
{
string sData = null;
sData = await reader.ReadLineAsync();
reader.DiscardBufferedData();
Console.WriteLine(sData);
// shows content on the console.
if (sData != null)
try
{
if (File.Exists(Environment.CurrentDirectory + "\\serverCOM\\" + clientName + "_get.txt"))
File.Delete(Environment.CurrentDirectory + "\\serverCOM\\" + clientName + "_get.txt");
File.WriteAllText(Environment.CurrentDirectory + "\\serverCOM\\" + clientName + "_get.txt", sData);
}
catch (Exception i)
{
Log.handleException(i);
}
}
I am assuming it is something simple to change on one of the programs, thank you in advance!

Categories