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);
Related
Currently I try to read and write Async to/from a network stream. My software is the Client part and the server can send informations on its own or respond to commands I send him.
So I need a socket which
reads all the time (in case the server sends status informations)
stops reading when I want to send commands (commands can be sequences of data with multible Write and Read operations)
So I thought it would be a good approach to create a Semaphore and a Background Task which handles the server sent messages and in case I want to send a command I block the semaphore and have full access to read/write operations to the socket.
Here is what I do currently.
private TcpClient _tcpClient = new TcpClient();
protected SemaphoreSlim ClientSemaphore { get; } = new SemaphoreSlim(1, 1);
public async Task ConnectAsync()
{
if (_tcpClient.Connected)
{
await DisconnectAsync();
}
await _tcpClient.ConnectAsync(Hostname, RemotePort);
//here the background Task is started
_ = AutoReceiveMessages();
}
private async Task AutoReceiveMessages()
{
while (_tcpClient.Connected)
{
//enter and lock semaphore
await ClientSemaphore.WaitAsync();
try
{
//read from socket until timeout (ms)
var msg = await ReadFromSocket(2000);
foreach (var cmd in SplitMessageInTelegrams(msg))
{
Console.WriteLine("MESSAGE --> " + cmd);
}
}
catch (Exception ex)
{
}
finally
{
//release semaphore
ClientSemaphore.Release();
}
}
}
private async Task<string> ReadFromSocket(double timeout = 0)
{
var buf = new byte[4096];
var stream = _tcpClient.GetStream();
//read from stream or timeout
var amountReadTask = stream.ReadAsync(buf, 0, buf.Length);
var timeoutTask = Task.Delay(TimeSpan.FromMilliseconds(timeout));
await Task.WhenAny(timeoutTask, amountReadTask)
.ConfigureAwait(false);
//timeout
if (!amountReadTask.IsCompleted)
{
throw new TimeoutException("Timeout");
}
//no timeout
return Encoding.ASCII.GetString(buf, 0, amountReadTask.Result);
}
But this do not work as I expected...
I use this methode to send a message to the server and in WireShark I see the server resonds with the same message
protected async Task SendTelegramAsync(ITelegram telegram)
{
await ClientSemaphore.WaitAsync();
try
{
_ = telegram ?? throw new ArgumentException($"{nameof(telegram)}");
if (!_tcpClient.Connected) throw new InvalidOperationException("Socket not connected!");
var buf = new byte[4096];
var stream = _tcpClient.GetStream();
var msg = Encoding.ASCII.GetBytes("\x02" + telegram.GetCommandMessage() + "\x03");
Console.WriteLine("WRITE --> " + msg);
await stream.WriteAsync(msg, 0, msg.Length);
//comment AutoReceiveMessage and remove comment from this
//and I get responses from the server
//var test = await ReadFromSocket(2000);
}
finally
{
ClientSemaphore.Release();
}
}
I know in this case I do not need the semaphore but later I want to create sequences so one command consists of multible writes and reads and as long as the command is executed I do not want to use the AutoReceiveMessages method.
The problem now is
If I use it like this I never get a response the ReadFromSocket method always get the timeout even when wireshark tell me the server has responded
But even better if I disable AutoReceiveMessages (just comment _ = AutoReceiveMessages()) and use ReadFromSocket directly in SendTelegramAsync() everything work as expected.
So I think the problem is something related to the background task and the ReadAsync but I couldnt figure it out...
Got It!
stream.DataAvailable is your friend (or my friend :)).
If I check before the ReadAsync if DataIsAvailable then I have no problem anymore.
if (_tcpClient.GetStream().DataAvailable)
var msg = await ReadFromSocket(DEFAULT_TIMEOUT);
That title is a little weird, but I have a UdpClient and it uses ReceiveAsync to listen for response from the remote endpoint after a SendAsync. The problem is that the remote endpoint is a very flimsy IoT device that will either close the connection, or never reply.
I want to timeout the ReceiveAsync so the socket can be released when the device decides to do nothing. I saw a genius comment by AJ Richardson here that suggests doing this:
Task.WhenAny(
client.ReceiveAsync(),
Task.Delay(5000)
);
I'm sure that works great, but if the ReceiveAsync is successful, I need to read the response, but because it's wrapped in Task.WhenAny, I have no idea how to do that.
Could anyone give me any suggestions? Thanks in advance!
Clarification
To clarify, here's my scenario. I have a Hangfire background job. It receives a data model and based on it sends a message to an IoT device using UDP. The problem is that the devices are flimsy and will not respond, which means the client will be awaiting forever.
If that happens then the client will be holding onto the port, and depending on how many times the job is queued I can eventually run out of ports since their clients are just stuck awaiting.
To avoid that, I want to timeout after a 5 second period and release the client's port and other resources. That is where Task.WhenAny comes in. Either the ReceiveAsync or Task.Delay calls will complete first and end the process.
However, if ReceiveAsync completes first, I need to capture the response from it and do further processing with it. How do I do that?
Here is a more complete code sample of what I'm working with.
var iotAddress = new IPAddress(iot.Ip);
var iotEndpoint = new IPEndPoint(iotAddress, iot.Port);
try {
using (var client = new UdpClient(0, AddressFamily.InterNetwork)) {
client.Connect(iotEndpoint);
await client.SendAsync(bytes, bytes.Length);
if (!iot.WaitForResponse) {
return;
}
// await the response of the IoT device
var response = await client.ReceiveAsync();
// OR
//
// await either the response of the IoT device,
// or the delay to complete, effectively creating
// a timeout.
var timeoutOrComplete = await Task.WhenAny(
client.ReceiveAsync(),
Task.Delay(5000)
);
// If a response was received before the "timeout"
// was triggered, how do I get it?
var response = timeoutOrComplete.???
}
} catch {
// Ignore
}
Try following :
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
public class UdpState
{
public UdpClient u;
public IPEndPoint e;
public string receivedMessage;
// Size of receive buffer.
public const int BufferSize = 256;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
}
public static ManualResetEvent receiveDone = new ManualResetEvent(false);
public static void Main()
{
string ip = "172.0.0.1";
int port = 11111;
IPAddress iotAddress = IPAddress.Parse(ip);
IPEndPoint iotEndpoint = new IPEndPoint(iotAddress, port);
byte[] bytes = Encoding.UTF8.GetBytes("Hello World");
UdpState state = new UdpState();
try {
using (UdpClient client = new UdpClient(0, AddressFamily.InterNetwork)) {
client.Connect(iotEndpoint);
state.e = iotEndpoint;
state.u = client;
// await the response of the IoT device
client.BeginReceive(new AsyncCallback(ReceiveCallback), state);
client.BeginSend(bytes, bytes.Length, iotEndpoint, new AsyncCallback(SendCallback), client);
receiveDone.WaitOne();
var response = state.receivedMessage;
}
} catch {
// Ignore
}
}
public static void ReceiveCallback(IAsyncResult ar)
{
UdpState state = ar.AsyncState as UdpState;
UdpClient u = state.u;
IPEndPoint e = state.e;
state.buffer = u.EndReceive(ar, ref e);
state.receivedMessage = Encoding.ASCII.GetString(state.buffer);
receiveDone.Set();
}
private static void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
UdpClient client = ar.AsyncState as UdpClient ;
// Complete sending the data to the remote device.
int bytesSent = client.EndSend(ar);
}
catch (Exception e)
{
Console.WriteLine(e.ToString());
}
}
}
}
I think I need async await for my program but I can't figure out how to do it. From GetData method I need send request to socket, and finally get socket data to same method. Need to pass data somehow from OnReceive to initial GetData method. Is it possible to implement await async tasks here? Here is simplified scheme:
AsyncCallback m_pfnLookupCallback;
Socket m_sock;
public void GetData()
{
string data;
if (condition) data = GetDataFromCache();
else data = GetDataFromNet(); /// !NEED AWAIT FOR SOCKET DATA HERE
//will process data here.
}
public string GetDataFromNet()
{
m_sock.Send(szCommand, iBytesToSend, SocketFlags.None);
WaitForData("s1");
}
public void WaitForData(string sSocketName)
{
m_pfnLookupCallback = new AsyncCallback(OnReceive);
m_sock.BeginReceive(m_szLookupSocketBuffer, 0, m_szLookupSocketBuffer.Length, SocketFlags.None, m_pfnLookupCallback, sSocketName);
}
private void OnReceive(IAsyncResult asyn)
{
int iReceivedBytes = 0;
iReceivedBytes = m_sockLookup.EndReceive(asyn);
string sData = Encoding.ASCII.GetString(m_szLookupSocketBuffer, 0, iReceivedBytes); //WHAT I NEED
}
p.s. I would avoid changing socket work if possible because they are used in other parts of program.
You can turn the old IAsyncResult pattern (APM) into async await quite easily. Here's an example of the socket call:
var byteCount = await Task.Factory.FromAsync(
(callback, s) =>
{
return clientSocket.BeginReceive(
m_szLookupSocketBuffer,
0,
cm_szLookupSocketBuffer.Length,
SocketFlags.None,
callback,
sSocketName);
},
result => clientSocket.EndReceive(result),
null);
I've been making a server. I am using TcpListener.AcceptTcpClientAsync() in an async method, but I have no idea how to actually make it work. My code right now is:
private static async void StartServer()
{
Console.WriteLine("S: Server started on port {0}", WebVars.ServerPort);
var listener = new TcpListener(WebVars.LocalIp, WebVars.ServerPort);
listener.Start();
var client = await listener.AcceptTcpClientAsync();
}
How do I process the client? Do I just continue coding and it will automagically make new threads of the same method or do I need to do some magic method that will do it for me?
Edit: current code:
private static Task HandleClientAsync(TcpClient client)
{
var stream = client.GetStream();
// do stuff
}
/// <summary>
/// Method to be used on seperate thread.
/// </summary>
private static async void RunServerAsync()
{
while (true)
{
Console.WriteLine("S: Server started on port {0}", WebVars.ServerPort);
var listener = new TcpListener(WebVars.LocalIp, WebVars.ServerPort);
listener.Start();
var client = await listener.AcceptTcpClientAsync();
await HandleClientAsync(client);
}
}
// all credit should go to c# 7.0 in a nutshell (Joseph Albahari & Ben Albahari)
async void RunServerAsync()
{
var listner = new TcpListener(IPAddress.Any, 9999);
listner.Start();
try
{
while (true)
await Accept(await listner.AcceptTcpClientAsync());
}
finally { listner.Stop(); }
}
const int packet_length = 2; // user defined packet length
async Task Accept(TcpClient client)
{
await Task.Yield();
try
{
using(client)
using(NetworkStream n = client.GetStream())
{
byte[] data = new byte[packet_length];
int bytesRead = 0;
int chunkSize = 1;
while (bytesRead < data.Length && chunkSize > 0)
bytesRead += chunkSize =
await n.ReadAsync(data, bytesRead, data.Length - bytesRead);
// get data
string str = Encoding.Default.GetString(data);
Console.WriteLine("[server] received : {0}", str);
// To do
// ...
// send the result to client
string send_str = "server_send_test";
byte[] send_data = Encoding.ASCII.GetBytes(send_str);
await n.WriteAsync(send_data, 0, send_data.Length);
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Nothing will magically create dedicated threads for you, although there are some threads used for IO completion which can come into play, particularly if you don't have a synchronization context that you need to return to.
You should decide whether you want your StartServer method to actually complete when it's accepted a single connection, or keep looping until you've been told to shut down.
Either way, you clearly need to decide how to handle the client too. Either you could start a new thread and use synchronous methods, or you could just use asynchronous IO to handle everything in the same thread. For example, to dump the incoming data to a file:
private Task HandleClientAsync(TcpClient client)
{
// Note: this uses a *synchronous* call to create the file; not ideal.
using (var output = File.Create("client.data"))
{
using (var input = client.GetStream())
{
// Could use CopyToAsync... this is just demo code really.
byte[] buffer = new byte[8192];
int bytesRead;
while ((bytesRead = await input.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await output.WriteAsync(buffer, 0, bytesRead);
}
}
}
}
(That's assuming the client will just terminate the connection when it's finished writing the data.) Aside from the File.Create call, this is all asynchronous - so there's no need to create a separate thread for it.
This is just an example, of course - real connection handling would usually be more complicated. If your real handling needs anything more compute-intensive, you may well want to consider using Task.Run to use the thread pool... that way it won't interfere with accepting more connections.
I have built a server that receives requests from a client and gives a response that depends on the request Type. If the request type is streaming, the server must send data array. While the server’s streaming data the client may send a stop request to stop the streaming. If the request and the response is transferred on the same TCP connection the server only receives the stop request when all the data has finished streaming to the client. I think I must use Asynchronous write to solve this problem. This is my code:
First I create a loop back to receive connection from clients:
while (!done)
{
try
{
Socket socket = listener.AcceptSocket();
ClientInteraction clIr = new ClientInteraction(socket, statusList);
Thread thread = new Thread(new ThreadStart(clIr.Process));
thread.Start();
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}
}
In Process function of ClientInteraction class :
Public void Process()
{
ns = new NetworkStream(socket);
while (true)
{
try
{
this.myReadBuffer = new byte[socket.ReceiveBufferSize];
this.numberOfBytesRead = ns.Read(myReadBuffer, 0, myReadBuffer.Length);
}
catch
{
break;
}
if (numberOfBytesRead == 0)
{
break;
}
else
{
HandleRequest(myReadBuffer, numberOfBytesRead);
}
}
}
In HandleRequest Function, if request’s STREAM, I will send data in an array to client:
Public void HanldeRequest(……)
{
myCompleteMessage = "";
myCompleteMessage =
String.Concat(myCompleteMessage, Encoding.ASCII.GetString(myReadBuffer, 0, numberOfBytesRead));
If(myCompleteMessage == “Stream”)
{
//I get data and call SendData function
foreach(.......)
{
//get data
........
SendData(data);
}
}
}
public void SendData(byte[] data)
{
try
{
//ns.Write(data, 0, data.Length);
ns.BeginWrite(data, 0, data.Length, new AsyncCallback(StreamData), null);
}
catch
{
}
}
public void StreamData(IAsyncResult asynResult)
{
if(asynResult != null)
ns.EndWrite(asynResult);
}
With this code, I connected with client, send data to client. But I still can’t receive Stop request until all data is streamed. Please show me the correct way to fix my problem. Thank you.
I think you can try using multithread to solve this problem. I have met this circumstance and multithread is a good choice to solve. You can create a thread to write and a thread to read.