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.
Related
I am using NetMQ v3.3.3.4 to develop a simple server(RouterSocket) - client(RequestSocket) scenario. It works as expected except for one thing.
Sometimes the server takes too long to return a response and the client reaches a timeout. This behavior is desired. The issue here is that the server does not detect that the client is already gone and it continues processing the request. At some point the processing is done and the server tries to return a response. The server never realizes that the client is not listening anymore and thinks that a response has been successfully delivered. This leads to a misleading user feedback and wrong log file entries.
Is it possible for the server to detect if a client is still waiting for a response?
Server
private void Listen()
{
using (var poller = new NetMQPoller())
using (var responseSocket = new RouterSocket())
using (var poisonedSocket = new ResponseSocket())
{
responseSocket.Bind(_bindServerString);
poisonedSocket.Bind(_bindTerminationString);
var keepAliveTimer = new NetMQTimer(KeepAliveInterval);
keepAliveTimer.Elapsed += (s, a) =>
{
_monitorPublisher.Status["KeepAlive"] = Application.LocalDateTime.Now.ToString();
_monitorPublisher.SendStatus();
};
poisonedSocket.ReceiveReady += (s, a) =>
{
a.Socket.ReceiveFrameBytes();
poller.Stop();
};
responseSocket.ReceiveReady += (s, a) =>
{
try
{
bool header = true;
byte[] response = null;
while (a.Socket.TryReceiveFrameBytes(out byte[] message))
{
// Using a ROUTER socket...
if (header)
{
// We have to first, wait for the first frame,
// which is the address (header) of the REQ socket.
// Afterwards, we have to wait for the second frame,
// which is 0 and act as a delimiter between the REQ address
// and the actual body of the request.
a.Socket.SendFrame(message, true);
// Once we have the header delimiter, we can be sure that
// the next frame is the actual request.
header = !(message.Length == 0);
}
else
{
// Parse the request and return a response
BridgeRequestReceived?.Invoke(message, out response);
a.Socket.SendFrame(response);
}
}
}
catch (Exception e)
{
Logger.Instance.Log(e);
}
};
poller.Add(keepAliveTimer);
poller.Add(responseSocket);
poller.Add(poisonedSocket);
Logger.Instance.Log($"Receiving requests on: {_bindServerString}", Application.LogCategory.Info);
poller.Run();
responseSocket.Close();
poisonedSocket.Close();
}
}
Client
private string SendRequest(IBridgeMessage request, out Exception e)
{
e = null;
string response = null;
using (var socket = new RequestSocket())
{
try
{
socket.Connect(_endpoint);
byte[] encryptedRequest = CryptoAES.StandardCrypto.Encrypt(Encoding.UTF8.GetBytes(NMTBridgeMessageFactory.Serialize(request)));
socket.SendFrame(encryptedRequest);
if (socket.TryReceiveFrameBytes(_timeout, out byte[] reply))
{
response = Encoding.UTF8.GetString(CryptoAES.StandardCrypto.Decrypt(reply));
}
else
{
e = new TimeoutException("Timeout occured!");
response = null;
}
}
catch (Exception ex)
{
e = ex;
response = null;
}
}
return response;
}
I expect the server detects a client disconnection.
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);
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.
I want to create for each request return response in socket c# and android.
I find the relevant socket and send a request, asking for the data I need.
After sending the request, I receive bytes until it sends the response. Then I stop receiving.
My server will need to handle many clients at once, and preferably multiple requests from a client at once. I need both the client and server to be able to receive messages at any time
I wrote this code:
message = Encoding.UTF8.GetString(dataRec,0,c);
dataRec = new byte[2048];
switch(message)
{
case "list-menu":
sendListMenu();
break;
case "login":
isLogin(message);
break;
}
login method
public void isLogin(string str){
string message = "";
Model_Users users;
dataSend=Encoding.UTF8.GetBytes("send-result");
newsocket.Send(dataSend);
//newsocket.close(); if close not receive
c = newsocket.Receive(dataRec);
message = Encoding.UTF8.GetString(dataRec,0,c);
XmlSerializer xml = new XmlSerializer(typeof(Model_Users));
using (TextReader reader = new StringReader(message))
{
if (reader != null)
{
users = (Model_Users)xml.Deserialize(reader);
MessageBox.Show(users.username);
dataSend = Encoding.UTF8.GetBytes("success-login");
newsocket.Send(dataSend);
newsocket.Close();
}
}
}
android code (client):
socket = new Socket();
socketAddress = new InetSocketAddress(cursor.getString(cursor.getColumnIndex("ip")), 9999);
socket.connect(socketAddress, 10000);
bufferWriter = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bufferWriter.write(getrequest);
bufferWriter.flush();
String rvdMsgTxt = "";
stringBuilder = new StringBuilder();
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
while ((rvdMsgTxt = bufferedReader.readLine()).equals("success-login")) {
stringBuilder.append(rvdMsgTxt);
bufferedReader.mark(100);
bufferedReader.reset();
}
bufferWriter.write(XMLConvertor.usersSerializeXML("user", "pass"));
bufferWriter.flush();
But this doesn't work.
this SOLVED by newsocket.Shutdown(SocketShutdown.Send);
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.