How to implement UDP without blocking main thread - c#

The data I am using arrives by UDP. I want to create several UDP connections without blocking the main thread. I have implemented UDP connections synchronously and asynchronously, however they both keep the main thread locked. My code never reaches 'Console.WriteLine("Past the Async")'
The goal is to have the UDP connections running in the background.
Can anyone provide some direction as to what to try next, or how to properly implement an async version of UDP that allows the main thread to still receive commands?
I comment out ReceiveUdpData() for the async version.
class Program
{
// The whole point of this is to not block the main thread.
static async Task Main(string[] args)
{
ReceiveUdpData();
Console.WriteLine("Past Receive UDP Data");
await foreach (var item in MessagesAsync())
{
Console.WriteLine(item);
}
Console.WriteLine("Past The Async");
}
// Synchronous connection to UDP.
public static void ReceiveUdpData()
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
var count = 0;
using (UdpClient client = new UdpClient(12345))
{
while (true)
{
Byte[] receiveBytes = client.Receive(ref remoteEndPoint);
count++;
Console.WriteLine(count);
}
}
}
// Async UDP connection
private static async IAsyncEnumerable<object> MessagesAsync()
{
IPEndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0);
var count = 0;
using (UdpClient client = new UdpClient(12345))
{
while (true)
{
UdpReceiveResult test = await client.ReceiveAsync();
count++;
yield return test.ToString();
}
}
}
}

await will "block" the current method by scheduling the rest of the method to run after the given task continues. It's somewhat similar (not semantically identical to Task.ContinueWith) so csharp Console.WriteLine("Past The Async") will execute only after all the messages are received.
You can not wait for the messages by enumerating the IAsyncEnumerable on a separate task in a "fire and forget" manner:
static async Task Main(string[] args)
{
PrintMessages();
Console.WriteLine("Past The Async");
}
public static async Task PrintMessages()
{
await foreach (var item in MessagesAsync())
{
Console.WriteLine(item);
}
}
But if you do that, your program will terminate as soon as Main exits, so you might actually want to wait, or maybe you have some other work you can perform.

this a basis of program i am using to use an async udp:
sample:
using System;
using System.Net.Sockets;
using System.Net;
class Program {
static void OnUpdateData(IAsyncResult result) {
UdpClient socket = result.AsyncState as UdpClient;
IPEndPoint source = new IPEndPoint(0, 0);
byte[] message = socket.EndReceive(result, ref source);
Console.WriteLine($"Received {message.Length} bytes from {source}");
// schedule the next receive operation once reading is done:
socket.BeginReceive(new AsyncCallback(OnUpdateData), socket);
}
static void Main(string[] args) {
UdpClient socket = new UdpClient(12345);
socket.BeginReceive(new AsyncCallback(OnUpdateData), socket);
//send message with same program or use another program
IPEndPoint target = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 12345);
// send a couple of sample messages:
for (int num = 1; num <= 3; num++) {
byte[] message = new byte[num];
socket.Send(message, message.Length, target);
}
Console.ReadKey();
}
}

Related

How do I stop using too much CPU in my async loop?

I have a basic TcpListener server that accepts TcpClient requests and sticks them in separate threads.
The server thread that accepts requests uses await _server.AcceptTcpClientAsync() so it returns cpu resources and doesn't use any cpu until it gets a client request.
My client loop calls await client.GetStream().ReadAsync but that's wrapped in a if (client.Connected && client.Available > 0) so if there is no data it just returns null, so nothing is being awaited.
The options I know of are to add a Thread.Sleep which is bad practice and will slow down my apps, use a EventWaitHandle but I'd have to know set that somehow or to remove the if (client.Connected && client.Available > 0) check, which would sit indefinitely waiting for data, so if the server went down the program would effectively be dead.
EDIT: Added client code
public class TcpServer
{
private TcpListener _server;
private bool _isRunning;
private object _lock = new object();
// Listener thread
public async void StartServer()
{
_server = new TcpListener("127.0.0.1", 1234);
_server.Start();
_isRunning = true;
Thread.CurrentThread.Name = "TcpServer";
while (_isRunning)
{
// Block until client connection
TcpClient newClient = await _server.AcceptTcpClientAsync();
// Create a thread to handle client connection
new Thread(new ParameterizedThreadStart(HandleClientConnection)).Start(newClient);
}
}
// Client Thread
public async void HandleClientConnection(object obj)
{
// Create worker object
var client = (TcpClient)obj;
{
ClientId = Guid.NewGuid()
};
// Read client data
while (client.Connected)
{
var msg = await client.ReadMessageAsync();
}
// Disconnected
}
}
// Read data from stream when available. Used on server and client
public static async Task<Message> ReadMessageAsync(this TcpClient client)
{
if (client.Connected && client.Available > 0)
{
int totalBytesRead = 0;
var data = new byte[client.Available];
while (totalBytesRead < client.Available)
{
totalBytesRead += await client.GetStream().ReadAsync(data, 0, client.Available);
}
return BinarySerializer.DeserializeMessage(data) as Message;
}
return null;
}
// Client Code
public async Task Start()
{
ConnectToServer();
while (_isRunning)
{
// Reconnect to server if needed.
if (!_tcpClient.Connected)
{
ConnectToServer();
}
// Wait for messages
var message = await _tcpClient.ReadMessageAsync();
HandleMessage(message);
}
}

TcpListener send heartbeat every 5 seconds and read message from client async

I'm writing a TcpListener service that runs as a Windows Service that a vendor software client will connect to. I can't change the client's implementation and must adhere to their spec.
I have the part that receives messages and returns a response working. The problem I have is the clients expect a heartbeat message (S0000E) to be sent every 5 seconds, to which it replies with the same message. I'm not sure how to add that functionality in among the async/await stuff I'm doing to handle the real messages received from the clients.
OnStart
_serverListenerTask = Task.Run(() => AcceptClientsAsync(_listener, _cancellationToken.Token));
AcceptClientsAsync
static async Task AcceptClientsAsync(TcpListener listener, CancellationToken ct)
{
var clientCounter = 0;
while (!ct.IsCancellationRequested)
{
TcpClient client = await listener.AcceptTcpClientAsync()
.ConfigureAwait(false);
clientCounter++;
await ReceiveMessageAsync(client, clientCounter, ct);
}
}
ReceiveMessageAsync
static async Task ReceiveMessageAsync(TcpClient client, int clientIndex, CancellationToken ct)
{
Log.Info("New client ({0}) connected", clientIndex);
using (client)
{
var buffer = new byte[4096];
var stream = client.GetStream();
while (!ct.IsCancellationRequested)
{
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15));
var amountReadTask = stream.ReadAsync(buffer, 0, buffer.Length, ct);
var completedTask = await Task.WhenAny(timeoutTask, amountReadTask)
.ConfigureAwait(false);
if (completedTask == timeoutTask)
{
var msg = Encoding.ASCII.GetBytes("Client timed out");
await stream.WriteAsync(msg, 0, msg.Length);
break;
}
var bytesRead = amountReadTask.Result;
if (bytesRead == 0)
{
// Nothing was read
break;
}
// Snip... Handle message from buffer here
await stream.WriteAsync(responseBuffer, 0, responseBuffer.Length, ct)
.ConfigureAwait(false);
}
}
Log.Info("Client ({0}) disconnected", clientIndex);
}
I thought I could add a heartbeat task to the Task.WhenAny, but that caused the heartbeat to always fire and I could never read the response. I also tried sending the heartbeat before the timeout and read tasks, which worked for sending, but then I was either reading the heartbeat response and not the next message in line or the timeout task would complete and disconnect the client. Essentially, if the heartbeat exchange is successful then the client shouldn't be disconnected after that 15 second delay.
Implementing TCP server-client is not a simple task. However, the following way of implementation, if you improve it to be more efficient in resources, can be a practical solution:
Server:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Server
{
public class Program
{
static List<SocketBuffer> clients = new List<SocketBuffer>();
public static void Main(string[] args)
{
//Receive from any IP, listen on port 65000 in this machine
var listener = new TcpListener(IPAddress.Any, 65000);
var t = Task.Run(() =>
{
while (true)
{
listener.Start();
var task = listener.AcceptTcpClientAsync();
task.Wait();
clients.Add(new SocketBuffer(task.Result, new byte[4096]));
}
});
t.Wait(); //It will remain here, do in a better way if you like !
}
}
/// <summary>
/// We need this class because each TcpClient will have its own buffer
/// </summary>
class SocketBuffer
{
public SocketBuffer(TcpClient client, byte[] buffer)
{
this.client = client;
stream = client.GetStream();
this.buffer = buffer;
receiveData(null);
}
private TcpClient client;
private NetworkStream stream;
private byte[] buffer;
private object _lock = new object();
private async void receiveData(Task<int> result)
{
if (result != null)
{
lock (_lock)
{
int numberOfBytesRead = result.Result;
//If no data read, it means we are here to be notified that the tcp client has been disconnected
if (numberOfBytesRead == 0)
{
onDisconnected();
return;
}
//We need a part of this array, you can do it in more efficient way if you like
var segmentedArr = new ArraySegment<byte>(buffer, 0, numberOfBytesRead).ToArray();
OnDataReceived(segmentedArr);
}
}
var task = stream.ReadAsync(buffer, 0, buffer.Length);
//This is not recursion in any sense because the current
//thread will be free and the call to receiveData will be from a new thread
await task.ContinueWith(receiveData);
}
private void onDisconnected()
{
//Add your code here if you want this event
}
private void OnDataReceived(byte[] dat)
{
//Do anything with the data, you can reply here. I will just pring the received data from the demo client
string receivedTxt = Encoding.ASCII.GetString(dat);
Console.WriteLine(receivedTxt);
}
}
}
Demo client:
using System;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Client
{
public class Program
{
public static void Main(string[] args)
{
TcpClient client = new TcpClient();
var task = client.ConnectAsync("localhost", 65000);
task.Wait();
if(client.Connected)
{
Console.WriteLine("Client connected");
var stream = client.GetStream();
var data = Encoding.ASCII.GetBytes("test");
stream.Write(data, 0, data.Length);
}
else
{
Console.WriteLine("Client NOT connected");
}
Thread.Sleep(60000);
}
}
}

AcceptTcpClient and AcceptTcpClientAsync difference

From what I understand, those lines:
var client = await listener.AcceptTcpClientAsync();
var client = listener.AcceptTcpClient();
should work the same way, but if I try to open, for example, 5k connections (without closing them), very soon listener (async) either stops responding or throws exception.
Anyone have idea what may be wrong?
Sample class:
class ListenerTest
{
static int connectionNumber = 0;
static int port = 23456;
public void StartListening(bool async)
{
var listener = new TcpListener(IPAddress.Any, port);
listener.Start();
if (async)
{
var task = HandleConnectionsAsync(listener);
task.Wait();
}
else
HandleConnections(listener);
}
async Task HandleConnectionsAsync(TcpListener listener)
{
while (true)
{
Console.Write("Waiting for async connection...");
var client = await listener.AcceptTcpClientAsync();
Console.WriteLine("OK #" + connectionNumber);
connectionNumber++;
}
}
void HandleConnections(TcpListener listener)
{
while (true)
{
Console.Write("Waiting for sync connection...");
var client = listener.AcceptTcpClient();
Console.WriteLine("OK #" + connectionNumber);
connectionNumber++;
}
}
public static void ConnectTest(int count)
{
var ep = new IPEndPoint(IPAddress.Loopback, port);
for (var i = 0; i < count; i++)
new TcpClient().Connect(ep);
}
}
Usage:
static void Main(string[] args)
{
var isAsync = true;
ThreadPool.QueueUserWorkItem(new WaitCallback(StartListening), isAsync);
ListenerTest.ConnectTest(5000);
}
static void StartListening(object state)
{
var my = new ListenerTest();
my.StartListening((bool)state);
}
Your test connections killed by GC, if you "pin" down your connections until end of test - you'll get your 5000 connections( i've just copy/pasted and fixed/tested your code ). Rewritten connection test:
public static void ConnectTest(int count)
{
var ep = new IPEndPoint(IPAddress.Loopback, port);
List<TcpClient> clients = new List<TcpClient>();
for (var i = 0; i < count; i++)
{
TcpClient cl = new TcpClient();
clients.Add(cl);
cl.Connect(ep);
}
}
Also please note that in "real world" conditions you need to add something like this before starting listener loop:
ThreadPool.SetMinThreads(100, 100);
This let your code work under "burst" connections count/network loading. We've just successfully "load tested" 7,5K connections under linux/mono.
You can't have 100,000 connections to a single machine. TCP/IP only has 16 bits for a port number (maximum 64k ports), and a good number of these are used (or reserved) for the OS or various services.
Normally, only 16,383 of these ports are available for incoming client connections, and you'll need to share them with all the other processes that use TCP/IP regularly.

Using .Net 4.5 Async Feature for Socket Programming

I've previously used BeginAccept() and BeginRead(), but with Visual Studio 2012 I want to make use of the new asynchronous (async, await) features in my socket server program.
How can I complete the AcceptAsync and ReceiveAsync functions?
using System.Net;
using System.Net.Sockets;
namespace OfficialServer.Core.Server
{
public abstract class CoreServer
{
private const int ListenLength = 500;
private const int ReceiveTimeOut = 30000;
private const int SendTimeOut = 30000;
private readonly Socket _socket;
protected CoreServer(int port, string ip = "0.0.0.0")
{
_socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_socket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
_socket.Listen(ListenLength);
_socket.ReceiveTimeout = ReceiveTimeOut;
_socket.SendTimeout = SendTimeOut;
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);
_socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
}
public void Start()
{
}
}
}
...because you're so determined, I put together a very simple example of how to write an echo server to get you on your way. Anything received gets echoed back to the client. The server will stay running for 60s. Try telnetting to it on localhost port 6666. Take time to understand exactly what's going on here.
void Main()
{
CancellationTokenSource cts = new CancellationTokenSource();
TcpListener listener = new TcpListener(IPAddress.Any, 6666);
try
{
listener.Start();
//just fire and forget. We break from the "forgotten" async loops
//in AcceptClientsAsync using a CancellationToken from `cts`
AcceptClientsAsync(listener, cts.Token);
Thread.Sleep(60000); //block here to hold open the server
}
finally
{
cts.Cancel();
listener.Stop();
}
}
async Task AcceptClientsAsync(TcpListener listener, CancellationToken ct)
{
var clientCounter = 0;
while (!ct.IsCancellationRequested)
{
TcpClient client = await listener.AcceptTcpClientAsync()
.ConfigureAwait(false);
clientCounter++;
//once again, just fire and forget, and use the CancellationToken
//to signal to the "forgotten" async invocation.
EchoAsync(client, clientCounter, ct);
}
}
async Task EchoAsync(TcpClient client,
int clientIndex,
CancellationToken ct)
{
Console.WriteLine("New client ({0}) connected", clientIndex);
using (client)
{
var buf = new byte[4096];
var stream = client.GetStream();
while (!ct.IsCancellationRequested)
{
//under some circumstances, it's not possible to detect
//a client disconnecting if there's no data being sent
//so it's a good idea to give them a timeout to ensure that
//we clean them up.
var timeoutTask = Task.Delay(TimeSpan.FromSeconds(15));
var amountReadTask = stream.ReadAsync(buf, 0, buf.Length, ct);
var completedTask = await Task.WhenAny(timeoutTask, amountReadTask)
.ConfigureAwait(false);
if (completedTask == timeoutTask)
{
var msg = Encoding.ASCII.GetBytes("Client timed out");
await stream.WriteAsync(msg, 0, msg.Length);
break;
}
//now we know that the amountTask is complete so
//we can ask for its Result without blocking
var amountRead = amountReadTask.Result;
if (amountRead == 0) break; //end of stream.
await stream.WriteAsync(buf, 0, amountRead, ct)
.ConfigureAwait(false);
}
}
Console.WriteLine("Client ({0}) disconnected", clientIndex);
}
You can use TaskFactory.FromAsync to wrap up Begin / End pairs into async-ready operations.
Stephen Toub has an awaitable Socket on his blog which wraps the more efficient *Async endpoints. I recommend combining this with TPL Dataflow to create a fully async-compatible Socket component.

Turning async socket Parallel and not only Concurrent in very intensive application using TPL

I'm writing an application that uses Socket and it will be very intensive then I really need use every core we have in our big server. I see the question ( how to using ThreadPool to run socket thread parallel? ) here in stackoverflow there is only one answer that point to this MSDN Sample.
But I think it point only how to make it Concurrent and not Parallel, here is someone asking How cpu intensive is opening a socket and its looks be very intensive, someone here tell its dont help TPL TaskFactory.FromAsync vs Tasks with blocking methods and someone teach how to do it here whith TaskFactory.FromAsync (Is there a pattern for wrapping existing BeginXXX/EndXXX async
methods into async tasks?).
How can I keep socket operations parallel and performant and if deal whith socket
problems like disconnections, half connected sockets and message boundaries are a headache in normal async way. How to deal with it if its put together TPL and Task.
see that:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace skttool
{
public class StateObject
{
public Socket workSocket = null;
public const int BufferSize = 1024;
public byte[] buffer = new byte[BufferSize];
public int bytesRead = 0;
public StringBuilder sb = new StringBuilder();
}
public class tool
{
//-------------------------------------------------
private ManualResetEvent evtConnectionDone = new ManualResetEvent(false);
private Socket skttool = null;
private bool running = false;
private StateObject state = null;
//-------------------------------------------------
toolConfig _cfg;
public tool(toolConfig cfg)
{
_cfg = cfg;
}
//-------------------------------------------------
public void socketListeningSet()
{
IPEndPoint localEndPoint;
Socket skttool;
byte[] bytes = new Byte[1024];
localEndPoint = new IPEndPoint(IPAddress.Any, _cfg.addressPort);
skttool = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
skttool.Bind(localEndPoint);
skttool.Listen(_cfg.maxQtdSockets);
}
//-------------------------------------------------
public void start()
{
running = true;
Task T1 = Task.Factory.StartNew(socketListeningSet);
T1.ContinueWith(prev =>
{
while (running)
{
evtConnectionDone.Reset();
Task<Socket> accepetChunk = Task<Socket>.Factory.FromAsync(
skttool.BeginAccept,
skttool.EndAccept,
accept,
skttool,
TaskCreationOptions.AttachedToParent);
accepetChunk.ContinueWith(accept, TaskContinuationOptions.NotOnFaulted | TaskCreationOptions.AttachedToParent);
evtConnectionDone.WaitOne();
}
});
}
//-------------------------------------------------
void accept(Task<Socket> accepetChunk)
{
state = new StateObject();
evtConnectionDone.Set();
state.workSocket = accepetChunk.Result;
Task<int> readChunk = Task<int>.Factory.FromAsync(
state.workSocket.BeginReceive,
state.workSocket.EndReceive,
state.buffer,
state.bytesRead,
state.buffer.Length - state.bytesRead,
null,
TaskCreationOptions.AttachedToParent);
readChunk.ContinueWith(read, TaskContinuationOptions.NotOnFaulted | TaskCreationOptions.AttachedToParent);
}
//-------------------------------------------------
void read(Task<int> readChunk)
{
state.bytesRead += readChunk.Result;
if (readChunk.Result > 0 && state.bytesRead < state.buffer.Length)
{
read();
return;
}
_data = doTask(_data);
Task<int> sendChunk = Task<int>.Factory.FromAsync(
state.workSocket.BeginSend,
state.workSocket.EndSend,
state.buffer,
state.bytesRead,
state.buffer.Length - state.bytesRead,
null,
TaskCreationOptions.AttachedToParent);
sendChunk.ContinueWith(send, TaskContinuationOptions.NotOnFaulted | TaskCreationOptions.AttachedToParent);
}
//-------------------------------------------------
void send(Task<int> readChunk)
{
state.workSocket.Shutdown(SocketShutdown.Both);
state.workSocket.Close();
}
//-------------------------------------------------
byte[] doTask(byte[] data)
{
return Array.Reverse(data);
}
//-------------------------------------------------
}
}
See this link about TPL and Traditional .NET Asynchronous Programming, it dont answer but maybe can help you. There is information about Asynchronous Programming Model (APM) and Event-based asynchronous pattern (EAP)

Categories

Resources