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());
}
}
}
}
Related
I'm trying to understand the backlog parameter of TcpListener class but I struggle on how to achieve maximum number of pending connections at same time so I can test it.
I have a sample async server and client code. MSDN says that the backlog is the maximum length of the pending connections queue. I made the server listen for connections all the time and the client is connecting 30 times. What I expect is after the 20th request to throw a SocketException in the client because the backlog is set to 20. Why doesn't it block it?
My second misunderstanding is do I really need to put my logic of the accepted connection in a new thread assuming there is a slow operation which takes around 10 seconds e.g. sending a file over the TCP? Currently, I put my logic in a new Thread, I know it's not the best solution and instead I should use a ThreadPool but the question is principal. I tested it by changing the client side's loop to 1000 iterations and if my logic is not in a new thread, the connections were getting blocked after the 200th connection probably because Thread.Sleep slows the main thread each time by 10 seconds and the main thread is responsible for all the accept callbacks. So basically, I explain it myself as the following: if I want to use the same concept, I have to put my AcceptCallback logic in a new thread like I did or I have to do something like the accepted answer here: TcpListener is queuing connections faster than I can clear them. Am I right?
Server code:
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace Server
{
class Program
{
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
static void Main(string[] args)
{
TcpListener listener = new TcpListener(IPAddress.Any, 80);
try
{
listener.Start(20);
while (true)
{
_mre.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), listener);
_mre.WaitOne();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AcceptCallback(IAsyncResult ar)
{
_mre.Set();
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
IPAddress ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
Console.WriteLine($"{ip} has connected!");
// Actually I changed it to ThreadPool
//new Thread(() =>
//{
// Console.WriteLine("Sleeping 10 seconds...");
// Thread.Sleep(10000);
// Console.WriteLine("Done");
//}).Start();
ThreadPool.QueueUserWorkItem(new WaitCallback((obj) =>
{
Console.WriteLine("Sleeping 10 seconds...");
Thread.Sleep(10000);
Console.WriteLine("Done");
}));
// Close connection
client.Close();
}
}
}
Client code:
using System;
using System.Net.Sockets;
namespace Client
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 30; i++)
{
Console.WriteLine($"Connecting {i}");
using (TcpClient client = new TcpClient()) // because once we are done, we have to close the connection with close.Close() and in this way it will be executed automatically by the using statement
{
try
{
client.Connect("localhost", 80);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console.ReadKey();
}
}
}
Edit: Since my second question might be a little bit confusing, I will post my code which includes sent messages and the question is should I leave it like that or put the NetworkStream in a new thread?
Server:
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
namespace Server
{
class Program
{
private static readonly ManualResetEvent _mre = new ManualResetEvent(false);
static void Main(string[] args)
{
// MSDN example: https://learn.microsoft.com/en-us/dotnet/framework/network-programming/asynchronous-server-socket-example
// A better solution is posted here: https://stackoverflow.com/questions/2745401/tcplistener-is-queuing-connections-faster-than-i-can-clear-them
TcpListener listener = new TcpListener(IPAddress.Any, 80);
try
{
// Backlog limit is 200 for Windows 10 consumer edition
listener.Start(5);
while (true)
{
// Set event to nonsignaled state
_mre.Reset();
Console.WriteLine("Waiting for a connection...");
listener.BeginAcceptTcpClient(new AsyncCallback(AcceptCallback), listener);
// Wait before a connection is made before continuing
_mre.WaitOne();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
private static void AcceptCallback(IAsyncResult ar)
{
// Signal the main thread to continue
_mre.Set();
TcpListener listener = (TcpListener)ar.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(ar);
IPAddress ip = ((IPEndPoint)client.Client.RemoteEndPoint).Address;
Console.WriteLine($"{ip} has connected!");
using (NetworkStream ns = client.GetStream())
{
byte[] bytes = Encoding.Unicode.GetBytes("test");
ns.Write(bytes, 0, bytes.Length);
}
// Use this only with backlog 20 in order to test
Thread.Sleep(5000);
// Close connection
client.Close();
Console.WriteLine("Connection closed.");
}
}
}
Client:
using System;
using System.Net.Sockets;
using System.Text;
namespace Client
{
class Program
{
static void Main(string[] args)
{
for (int i = 0; i < 33; i++)
{
Console.WriteLine($"Connecting {i}");
using (TcpClient client = new TcpClient()) // once we are done, the using statement will do client.Close()
{
try
{
client.Connect("localhost", 80);
using (NetworkStream ns = client.GetStream())
{
byte[] bytes = new byte[100];
int readBytes = ns.Read(bytes, 0, bytes.Length);
string result = Encoding.Unicode.GetString(bytes, 0, readBytes);
Console.WriteLine(result);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
Console.ReadKey();
}
}
}
The listen backlog is defined in RFC 6458 and tells the OS the maximum number of sockets allowed in the accept queue.
Incoming connections are placed in this queue by the TCP/IP stack and removed when the server calls Accept to handle the new connection.
In your question, both versions of the server code call Accept in a loop from the main thread, and wait for AcceptCallback to start before making another accept call. This results in quite fast draining of the queue.
To demonstrate listen queue overflow, its easiest to slow down your server's rate of accepting - E.g. slow it down to zero:
var serverEp = new IPEndPoint(IPAddress.Loopback, 34567);
var serverSocket = new TcpListener(serverEp);
serverSocket.Start(3);
for (int i = 1; i <= 10; i++)
{
var clientSocket = new TcpClient();
clientSocket.Connect(serverEp);
Console.WriteLine($"Connected socket {i}");
}
In your examples you could just add a sleep at the end of the Accept loop in the main thread, and increase the connection rate.
In the real world, the optimal backlog depends on:
The rate that the clients / internet / OS can fill the queue
The rate that the OS / server can process the queue
I don't recommend using Thread directly, here's how the server looks using Task and Socket Task Extensions:
static async Task Main(string[] args)
{
var server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
server.Bind(new IPEndPoint(IPAddress.Any, 80));
server.Listen(5);
while (true)
{
var client = await server.AcceptAsync();
var backTask = ProcessClient(client);
}
}
private static async Task ProcessClient(Socket socket)
{
using (socket)
{
var ip = ((IPEndPoint)(socket.RemoteEndPoint)).Address;
Console.WriteLine($"{ip} has connected!");
var buffer = Encoding.Unicode.GetBytes("test");
await socket.SendAsync(buffer, SocketFlags.None);
}
Console.WriteLine("Connection closed.");
}
i've made some program that starts an asynchronous socket that handles all client request.
Socket starts before Form1 is called, and works fine
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
AsynchronousServer ascSv = new AsynchronousServer();
Application.Run(new Form1());
if (ascSv != null)
ascSv.Stop();
}
}
--Edited--- (Added AsynchronousServer.cs)
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;
using System.Windows.Forms;
namespace Server
{
public class StateObject
{
// Client socket.
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 1024;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
// Received data string.
public StringBuilder sb = new StringBuilder();
}
public class AsynchronousServer
{
public ManualResetEvent allDone = new ManualResetEvent(false);
Socket listener;
public Thread t;
public AsynchronousServer()
{
t = new Thread(StartListening);
t.Start();
}
public void Stop()
{
try
{
listener.Shutdown(SocketShutdown.Both);
listener.Disconnect(false);
try
{
listener.Close();
listener.Dispose();
}
catch { }
}
catch
{
}
if (t!=null &&t.IsAlive)
{
t.Abort();
t = null;
}
listener = null;
}
public void StartListening()
{
// Establish the local endpoint for the socket.
// The DNS name of the computer
IPHostEntry ipHostInfo = Dns.GetHostEntry(Dns.GetHostName());
IPAddress ipAddress = ipHostInfo.AddressList[0];
IPEndPoint localEndPoint = new IPEndPoint(IPAddress.Parse("192.168.100.115"), 11000);
// Create a TCP/IP socket.
listener = new Socket(AddressFamily.InterNetwork,
SocketType.Stream, ProtocolType.Tcp);
// Bind the socket to the local endpoint and listen for incoming connections.
try
{
listener.Bind(localEndPoint);
listener.Listen(100);
while (true)
{
// Set the event to nonsignaled state.
allDone.Reset();
// Start an asynchronous socket to listen for connections.
//Console.WriteLine("Waiting for a connection...");
listener.BeginAccept(
new AsyncCallback(AcceptCallback),
listener);
// Wait until a connection is made before continuing.
allDone.WaitOne();
}
}
catch
{
//MessageBox.Show(e.Message);
}
}
public void AcceptCallback(IAsyncResult ar)
{
try
{
// Signal the main thread to continue.
allDone.Set();
// Get the socket that handles the client request.
Socket listener = (Socket)ar.AsyncState;
Socket handler = listener.EndAccept(ar);
// Create the state object.
StateObject state = new StateObject();
state.workSocket = handler;
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
catch
{
}
}
public void ReadCallback(IAsyncResult ar)
{
try
{
String content = String.Empty;
// Retrieve the state object and the handler socket
// from the asynchronous state object.
StateObject state = (StateObject)ar.AsyncState;
Socket handler = state.workSocket;
// Read data from the client socket.
int bytesRead = handler.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
state.sb.Append(Encoding.ASCII.GetString(
state.buffer, 0, bytesRead));
// Check for end-of-file tag. If it is not there, read
// more data.
content = state.sb.ToString();
if (content.IndexOf("<EOF>") > -1)
{
// All the data has been read from the
// client. Display it on the console.
//Console.WriteLine("Read {0} bytes from socket. \n Data : {1}",content.Length, content);
// Echo the data back to the client.
//Choose what to do with the packet
string callBack= ClientController.GenerateResponseTo(content);
//Choose what server has to reply to client
Send(handler, #callBack+"*<EOF>");
//Send(handler, #"N:\tmp\2parts\save.cnf*1*<EOF>");
}
else
{
// Not all data received. Get more.
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0,
new AsyncCallback(ReadCallback), state);
}
}
}
catch { }
}
private void Send(Socket handler, String data)
{
try
{
// Convert the string data to byte data using ASCII encoding.
byte[] byteData = Encoding.ASCII.GetBytes(data);
// Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0,
new AsyncCallback(SendCallback), handler);
}
catch { }
}
private void SendCallback(IAsyncResult ar)
{
try
{
// Retrieve the socket from the state object.
Socket handler = (Socket)ar.AsyncState;
// Complete sending the data to the remote device.
int bytesSent = handler.EndSend(ar);
//Console.WriteLine("Sent {0} bytes to client.", bytesSent);
handler.Shutdown(SocketShutdown.Both);
handler.Close();
}
catch
{
}
}
}
}
Once i'm on GUI clients can connect to server to ask for they answer and server replies an sleep packet untill user inputs a valid path on GUI and clicks START.
Well that also works fine.
My issue is that when a client is succesfully conected it starts sending a callback to the server and server outputs its callback in a progressbar from a custom control i've made and that also "works" but the issue is:
If i keep the GUI on the server start tab. All works fine, clients get their answers and server adds and updates client's progress bar. BUT when i change the tab controll to the tab where the progress bar of all clients are displayed, server stops sending any replys to clients. Even if i go back to the server start tab it doesn't reply anymore.
I'm so hardstuck on this. Does anyone know where does my error come from?
I also upladed some pictures of a debug client and my issue:
Client connected to server and getting answers:
Changeing GUI tab and server stopping:
Problem solved. Thanks to Aram Kocharyan and Mong Zhu.
The error was that I was trying to access a GUI element from a different thread.
To modify a GUI element from another thread must use Invoke method of controll (Invoke calls the method from the thread that owns the component)
Example:
Form1.GetInstance.flowLayoutPanel_progress.Invoke(
new Action(() => Parse0(splited[1], out toReturn)));
I'm trying to figure out how I can send & receive data via the UDP protocol using C# as a client, and having a JS server running that will transmit a "response" packet for testing purposes.
Below is the UDP class that I made for testing, it's simply just 2 threads:
One that read the received data from UDP and another thread for sending data.
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.Threading;
namespace UDPTesting {
class UDPHandler {
private int receivePort, sendPort;
private string serverIP;
private IPEndPoint sendEndPoint, receiveEndPoint;
public UDPHandler(string serverIP, int receivePort, int sendPort) {
this.serverIP = serverIP;
this.receivePort = receivePort;
this.sendPort = sendPort;
this.sendEndPoint = new IPEndPoint(IPAddress.Parse(this.serverIP), this.sendPort);
this.receiveEndPoint = new IPEndPoint(IPAddress.Parse(this.serverIP), this.receivePort);
this.readerUdpClient();
this.senderUdpClient();
}
void readerUdpClient() {
UdpClient readerClient = new UdpClient();
IPEndPoint localEndpoint = new IPEndPoint(IPAddress.Any, 3000);
readerClient.Client.Bind(localEndpoint); //Tried both Connect and Bind
//readerClient.Connect(this.receiveEndPoint);
Thread t = new Thread(() => {
Console.WriteLine("Awaiting data from server...");
var remoteEP = new IPEndPoint(IPAddress.Any, 3000);
byte[] bytesReceived = readerClient.Receive(ref remoteEP);
//The above throws: System.InvalidOperationException: 'You must call the Bind method before performing this operation'
Console.WriteLine("Received data from " + remoteEP.ToString());
});
t.Start();
}
void senderUdpClient() {
UdpClient senderClient = new UdpClient();
senderClient.Connect(this.sendEndPoint);
string sendString = "1;2;3";
byte[] bytes = toBytes(sendString);
Thread t = new Thread(() => {
while (true) {
senderClient.Send(bytes, bytes.Length);
Thread.Sleep(1000);
}
});
t.Start();
}
public byte[] toBytes(string text) {
return Encoding.UTF8.GetBytes(text);
}
public string fromBytes(byte[] bytes) {
return Encoding.UTF8.GetString(bytes);
}
}
}
Additionally my "main" for my program is this:
using System;
using System.Threading;
namespace UDPTesting {
class Program {
static void Main(string[] args) {
string serverIP = "46.101.102.243";
int sendPort = 41234;
int receivePort = 3000;
UDPHandler handler = new UDPHandler(serverIP, receivePort, sendPort);
}
}
}
How can I read the response that the server sends in the client, at the same time as I send data from the client to the server?
We tested it individually:
1) Sending a UDP packet from client -> server works, as I can see that the server receives the packet.
2) Sending a UDP packet from server -> client works, as I can see the client receives the packet.
3) When the client tries to send and read simultaneously, it will send data to the server, but will not read the response.
Any help would be greatly appreciated!
Your receiving function should work like this
void readerUdpClient()
{
new Thread(() => {
UdpClient readerClient = new UdpClient(receivePort);
Console.WriteLine("Awaiting data from server...");
var remoteEP = new IPEndPoint(IPAddress.Any, 0);
byte[] bytesReceived = readerClient.Receive(ref remoteEP);
Console.WriteLine($"Received {bytesReceived.Length} bytes from {remoteEP}");
}).Start();
}
The UdpClient constructor that takes a port automatically binds the local end point for you.
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'm trying to use UDP over LAN, as you can see here I send one package with one pc to the other, but is it possible to send packets while you are still listining because when I start receiving the process stops responding.
I know this has something to do with Threads but I need a little help.
I appreciate all help, thanks in advance.
UdpClient client = new UdpClient();
public void SendPacket()
{
byte[] packet = Encoding.ASCII.GetBytes(DateTime.Now.ToString("HH:mm:ss:ff"));
client.Send(packet, packet.Length, tbIP.Text, 444);
dgvSend.Rows.Add(DateTime.Now.ToString("HH:mm:ss:ff"));
}
public void ReceivePacket()
{
client = new UdpClient(444);
IPEndPoint server = new IPEndPoint(IPAddress.Any, 0);
byte[] packet = client.Receive(ref server);
dgvReceiv.Rows.Add(Encoding.ASCII.GetString(packet), DateTime.Now.ToString("HH:mm:ss:ff"));
}
As soon as you Receive something you need to start another Receive in order to receive something from someone else.
Typically you'd use asynchronous IO if you want to receive multiple connections. For example:
var client = new UdpClient(endPoint);
AsyncCallback callback = null;
callback = ar =>
{
IPEndPoint newIncomingEndPoint = endPoint;
byte[] data = client.EndReceive(ar, ref newIncomingEndPoint);
client.BeginReceive(callback, null);
// TODO: do something with data
};
client.BeginReceive(callback, null);
Or, if you're more comfortable with something that doesn't use anonymous methods (from http://msdn.microsoft.com/en-us/library/system.net.sockets.udpclient.beginreceive.aspx):
public static bool messageReceived = false;
public static void ReceiveCallback(IAsyncResult ar)
{
UdpClient u = (UdpClient)((UdpState)(ar.AsyncState)).u;
IPEndPoint e = (IPEndPoint)((UdpState)(ar.AsyncState)).e;
Byte[] receiveBytes = u.EndReceive(ar, ref e);
string receiveString = Encoding.ASCII.GetString(receiveBytes);
Console.WriteLine("Received: {0}", receiveString);
messageReceived = true;
}
public static void ReceiveMessages()
{
// Receive a message and write it to the console.
IPEndPoint e = new IPEndPoint(IPAddress.Any, listenPort);
UdpClient u = new UdpClient(e);
UdpState s = new UdpState();
s.e = e;
s.u = u;
Console.WriteLine("listening for messages");
u.BeginReceive(new AsyncCallback(ReceiveCallback), s);
// Do some work while we wait for a message. For this example,
// we'll just sleep
while (!messageReceived)
{
Thread.Sleep(100);
}
}
If you don't use async IO you can't receive another connection while you're processing the existing Receive--so you have a huge gap in time where something that wants to connect might get refused.