Trouble with Task.WhenAny - c#

I am using .NET framework to create a server, which listens on two ports on localhost. It is a simple console application.
It works when I keep connecting to one of the ports, but after I connect to first, another does not respond. First still is alive.
Here is my code:
static void Main(string[] args)
{
IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
List<TcpListener> listeners = new List<TcpListener>()
{
new TcpListener(hostIP, 6060),
new TcpListener(hostIP, 6061)
};
foreach (TcpListener listener in listeners)
{
listener.Start();
}
try
{
while (true)
{
Socket socket = AcceptAnyConnection(listeners).Result;
NetworkStream stream = new NetworkStream(socket);
byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
stream.Write(bytes, 0, bytes.Length);
//stream.Close();
socket.Close();
}
}
finally
{
foreach (TcpListener listener in listeners)
{
listener.Stop();
}
}
}
private static async Task<Socket> AcceptAnyConnection(List<TcpListener> listeners)
{
List<Task<Socket>> tasks = new List<Task<Socket>>();
foreach (TcpListener listener in listeners)
{
tasks.Add(AcceptConnection(listener));
}
Task<Socket> completedTask = await Task.WhenAny(tasks);
return await completedTask;
}
private static async Task<Socket> AcceptConnection(TcpListener listener)
{
Socket socket = await listener.AcceptSocketAsync();
return socket;
}
await Task.WhenAny() blocks if I connect to another port.
I must be doing something wrong, but I am not sure what.
BTW, I did try the same with .NET Core console application, and it works fine.
Thanks

I'd suggest refactoring your code to something like this, and taking it from there. That is, run an infinite loop for each listener. That avoids problems with making sure that you only call AcceptTcpClientAsync once at a time for each client.
(Note there's no code to actually stop the listeners. Also completely untested - please use it only as an indication of the sort of approach to take)
static void Main(string[] args)
{
IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
List<TcpListener> listeners = new List<TcpListener>()
{
new TcpListener(hostIP, 6060),
new TcpListener(hostIP, 6061)
};
var listenerTasks = listeners.Select(x => RunTcpListener(x)).ToArray();
Task.WaitAll(listenerTasks);
}
private static async Task RunTcpListener(TcpListener listener)
{
listener.Start();
try
{
while (true)
{
using (var client = await listener.AcceptTcpClientAsync())
{
var stream = client.GetStream();
byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
stream.Write(bytes, 0, bytes.Length);
client.Close();
}
}
}
finally
{
listener.Stop();
}
}

Here is my code, after I followed a suggestion by canton7 to move the task list outside of loop and move add and remove tasks "as we go". Probably, I will have to look at it to clean it up, but the idea works:
static void Main(string[] args)
{
IPAddress hostIP = Dns.GetHostAddresses("127.0.0.1")[0];
List<TcpListener> listeners = new List<TcpListener>()
{
new TcpListener(hostIP, 6060),
new TcpListener(hostIP, 6061)
};
ProcessConnections(listeners).Wait();
}
private async static Task SendData(Socket socket)
{
NetworkStream stream = new NetworkStream(socket);
byte[] bytes = Encoding.UTF8.GetBytes(DateTime.Now.ToString());
await stream.WriteAsync(bytes, 0, bytes.Length);
socket.Close();
}
private static async Task ProcessConnections(List<TcpListener> listeners)
{
foreach (TcpListener listener in listeners)
{
listener.Start();
}
try
{
List<Task<Socket>> tasks = new List<Task<Socket>>();
foreach (TcpListener listener in listeners)
{
tasks.Add(AcceptConnection(listener));
}
while (true)
{
int i = Task.WaitAny(tasks.ToArray());
Socket socket = await tasks[i];
await SendData(socket);
tasks.RemoveAt(i);
tasks.Insert(i, AcceptConnection(listeners[i]));
}
}
finally
{
foreach (TcpListener listener in listeners)
{
listener.Stop();
}
}
}
private static async Task<Socket> AcceptConnection(TcpListener listener)
{
Socket socket = await listener.AcceptSocketAsync();
return socket;
}

Related

How to resolve "Address already in use" exception with TcpListener

I have a requirement to use C# for a system that will do the following:
Connect to a remote host from a class method Method1
Continuously send requests to the remote host in 10 seconds intervals to maintain the connection established in step 1 in another class method Method2
In another class method, Method3, listen to the same port from where the requests in steps 1 and 2 were sent
But the problem I have is that when I try step 3, I get the exception
Address already in use
The following is my code showing the 3 methods
public static async Task Method1()
{
TcpClient _client = new TcpClient();
_client = new TcpClient();
await _client.ConnectAsync("IPAddress", 1234);
var localEndpoint = (IPEndPoint)_client.Client.LocalEndPoint;
sourcePort = localEndpoint.Port;
AppStatics.SourcePort = sourcePort;
var _stream = _client.GetStream();
await _stream.WriteAsync("...");
Task.Run(() => Method2(_stream));
Method3();
}
public static async Task Method2(NetworkStream stream)
{
//Start trying to connect to the remote server here
Console.WriteLine("Checking the connection with the USSD gateway...");
var _shakeTimer = new System.Timers.Timer(10000);
_shakeTimer.Elapsed += async (object source, ElapsedEventArgs e) => await SendNetworkConnectionCheck(stream);
_shakeTimer.AutoReset = true;
_shakeTimer.Enabled = true;
}
private static async Task<bool> SendNetworkConnectionCheck(NetworkStream stream)
{
stream.Write("...");
}
public static void Method3()
{
TcpListener listener = new TcpListener(IPAddress.Any, AppStatics.SourcePort);
listener.ExclusiveAddressUse = false;
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
try
{
listener.Stop();
listener.Start();
while (true)
{
TcpClient acceptTask = listener.AcceptTcpClient();
TcpClient incomingClient = acceptTask;
}
}
} catch (SocketException sex)
{
if (sex.SocketErrorCode == SocketError.AddressAlreadyInUse)
{
listener.Stop();
listener = new TcpListener(IPAddress.Any, AppStatics.SourcePort);
listener.ExclusiveAddressUse = false;
listener.Server.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);
listener.Start();
}else
{
Console.WriteLine(sex.InnerException?.Message ?? sex.Message);
}
}
catch (Exception ex)
{
Console.WriteLine("There was error while trying to listen/handle incoming message");
string errMsg = ex.InnerException?.Message ?? ex.Message;
Console.WriteLine(errMsg);
Console.WriteLine(ex.StackTrace?.ToString() ?? ex.ToString());
}
}
I will appreciate any guidance to get this resolved.
Thank you.

Multiple TCPServer/Client C#

I am trying to learn C# programming language. I have a very simple question here. I wanted to make TCPServer and TCPClient. but I couldn't quite do what I wanted to do. What I want is to have 4 clients on 1 server and they can talk to each other. I want the names of the people speaking to be determined individually. Please can anyone help with this? (Sorry for bad english)
/Server Code/
namespace SimpleTcpSrvr
{
class Program
{
//private static object mTcpClient;
static void Main(string[] args)
{
Console.OutputEncoding = Encoding.UTF8;
int asd;
byte[] data = new byte[1024];
IPEndPoint asd2 = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1302);
Socket newsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
newsocket.Bind(asd2);
newsocket.Listen(100);
Console.WriteLine("waiting for connection...");
Socket client = newsocket.Accept();
IPEndPoint clientep = (IPEndPoint)client.RemoteEndPoint;
var socket = (Socket)client;
Console.WriteLine((string.Format("New connection: " + socket.RemoteEndPoint.ToString())));
string welcome = "Chat Server";
data = Encoding.UTF8.GetBytes(Welcome my chat server);
client.Send(data, data.Length, SocketFlags.None);
string input;
while (true)
{
data = new byte[1024];
asd = client.Receive(data);
if (asd == 0)
break;
Console.WriteLine("TCPClient: " + Encoding.UTF8.GetString(data, 0, asd));
input = Console.ReadLine();
Console.SetCursorPosition(0, Console.CursorTop - 1);
Console.WriteLine("You: " + input);
client.Send(Encoding.UTF8.GetBytes(input));
}
Console.WriteLine("{0}'sinin bağlantısı kesildi.", clientep.Address);
client.Close();
newsocket.Close();
Console.ReadLine();
}
/Client Code/
namespace TCPClient
{
public class TcpClient
{
static void Main(string[] args)
{
Console.OutputEncoding = Encoding.ASCII;
byte[] data = new byte[1024];
string input, stringData;
IPEndPoint asd2 = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 1302);
Socket newsocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
try
{
newsocket.Connect(asd2);
}
catch (SocketException e)
{
Console.WriteLine("cant connect server");
Console.WriteLine(e.ToString());
return;
}
int asd = newsocket.Receive(data);
stringData = Encoding.UTF8.GetString(data, 0, asd);
Console.WriteLine(stringData);
while (true)
{
input = Console.ReadLine();
Console.SetCursorPosition(0, Console.CursorTop - 1);
Console.WriteLine("You: " + input);
newsocket.Send(Encoding.UTF8.GetBytes(input));
data = new byte[1024];
asd = newsocket.Receive(data);
stringData = Encoding.UTF8.GetString(data, 0, asd);
byte[] utf8string = Encoding.UTF8.GetBytes(stringData);
Console.WriteLine("TCPServer:" + stringData);
}
Console.WriteLine("connection lost from server...");
newsocket.Shutdown(SocketShutdown.Both);
newsocket.Close();
Console.WriteLine("disconnected!");
Console.ReadLine();
}
}
}
Firstly, it has to be said, there are a million-and-one edge cases when working with sockets - unless you are actually writing a new transport-protocol to run over TCP, you'd be much better off investing your time into learning an existing transport such as HTTP or gRPC.
With that disclaimer out of the way:
Use TcpListener() instead of Socket() in your server.
Use TcpClient() instead of Socket() in your client.
Your server needs to be able to simultaneously handle multiple clients, for this, use the Task-based Asyncronous Pattern (TAP).
So in your server, you need an instance of TcpClient() for every connection that your server accepts().
Start with a place to store all of your Tasks, e.g.,
static List<Task> Tasks = new();
Next you need a TcpListener which accepts incomming connections and spawns a Task to manage the TcpClient associated with that connection e.g.,
static async Task RunServerAsync()
{
TcpListener tcpListener = new(IPAddress.Loopback, 9999);
tcpListener.Start();
while (true)
{
var tcpClient = await tcpListener.AcceptTcpClientAsync();
Tasks.Add(Task.Run(() => RunClientAsync(tcpClient)));
}
}
A simple TcpClient Task would look something like this
static async Task RunClientAsync(TcpClient tcpClient)
{
Console.WriteLine($"Connection from: [{tcpClient.Client.RemoteEndPoint}]");
var reader = new StreamReader(tcpClient.GetStream());
while (true)
{
var line = await reader.ReadLineAsync();
Console.WriteLine($"{tcpClient.Client.RemoteEndPoint}: {line}");
}
}
You can tie this together in a Main() like this:
static async Task Main(string[] args)
{
await Task.Run(() => RunServerAsync());
}
Now you have a very simple echo-line server that will accept connections from as many clients as you can throw at it.
To wrap it up, you could use the TAP to create clients, for your testing, maybe something like:
static async Task RunClientAsync(string message)
{
var tcpClient = new TcpClient("127.0.0.1", 9999);
StreamWriter sw = new(tcpClient.GetStream());
tcpClient.NoDelay = true;
while(true)
{
await sw.WriteLineAsync(message);
await sw.FlushAsync();
await Task.Delay(1000);
}
}
And of course you'd need to update your Main to support this, e.g.,
static async Task Main(string[] args)
{
_ = Task.Run(() => RunServerAsync());
await Task.Delay(1000); // give the server a sec to start
_ = Task.Run(() => RunClientAsync("This is from client1"));
_ = Task.Run(() => RunClientAsync("Client2 is here!!"));
_ = Task.Run(() => RunClientAsync("And I am client3"));
await Task.Delay(int.MaxValue);
}
Of course in a real application you'd never fire and forget your Tasks like that.
Full code for the sake of completeness:
class Program
{
static List<Task> Tasks = new();
static async Task RunClientAsync(TcpClient tcpClient)
{
Console.WriteLine($"Connection from: [{tcpClient.Client.RemoteEndPoint}]");
var reader = new StreamReader(tcpClient.GetStream());
while (true)
{
var line = await reader.ReadLineAsync();
Console.WriteLine($"{tcpClient.Client.RemoteEndPoint}: {line}");
}
}
static async Task RunServerAsync()
{
TcpListener tcpListener = new(IPAddress.Loopback, 9999);
tcpListener.Start();
while (true)
{
var tcpClient = await tcpListener.AcceptTcpClientAsync();
Tasks.Add(Task.Run(() => RunClientAsync(tcpClient)));
}
}
static async Task Main(string[] args)
{
_ = Task.Run(() => RunServerAsync());
await Task.Delay(1000); // give the server a sec to start
_ = Task.Run(() => RunClientAsync("This is from client1"));
_ = Task.Run(() => RunClientAsync("Client2 is here!!"));
_ = Task.Run(() => RunClientAsync("And I am client3"));
await Task.Delay(int.MaxValue);
}
static async Task RunClientAsync(string message)
{
var tcpClient = new TcpClient("127.0.0.1", 9999);
StreamWriter sw = new(tcpClient.GetStream());
tcpClient.NoDelay = true;
while(true)
{
await sw.WriteLineAsync(message);
await sw.FlushAsync();
await Task.Delay(1000);
}
}
}

How to run async task in background?

I need to forward the port of running service in k8s cluster. So I have use the example provided in github repo to do port forward for specific service. Now I would like to use the example in my test but when I call port forward method then I always get web socket exception but if I written the same code in console application then I don't get any exception it run perfectly fine.
private async Task<bool> ForwardPortOperation(string podName, int[] originalPort, int forwardPort)
{
var pod = GetPodObject(podName);
var webSocket = await _config.GetK8SClient().WebSocketNamespacedPodPortForwardAsync(pod.Metadata.Name, pod.Metadata.NamespaceProperty, originalPort, WebSocketProtocol.V4BinaryWebsocketProtocol);
var demux = new StreamDemuxer(webSocket);
demux.Start();
var stream = demux.GetStream((byte?)0, (byte?)0);
IPAddress ipAddress = IPAddress.Loopback;
IPEndPoint localEndPoint = new IPEndPoint(ipAddress, forwardPort);
Socket listener = new Socket(ipAddress.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
listener.Bind(localEndPoint);
listener.Listen(100);
Socket handler = null;
var accept = Task.Run(() =>
{
while (true)
{
handler = listener.Accept();
var bytes = new byte[4096];
while (true)
{
int bytesRec = handler.Receive(bytes);
stream.Write(bytes, 0, bytesRec);
if (bytesRec == 0 || Encoding.Default.GetString(bytes, 0, bytesRec).IndexOf("<EOF>", StringComparison.InvariantCultureIgnoreCase) > -1)
{
break;
}
listener.Close();
}
}
});
var copy = Task.Run(() =>
{
var buff = new byte[4096];
while (true)
{
var read = stream.Read(buff, 0, 4096);
handler.Send(buff, read, 0);
}
});
await accept;
await copy;
return true;
}
Port forward method:
public bool PortForward(string podName, int[] originalPort, int forwardPort)
{
return Task.Run(() => ForwardPortOperation(podName, originalPort, forwardPort)).Result;
}
Nunit test project:
[Test]
public void VerifyPortForward()
{
new Pod(_config).PortForward("web_service_application", new int[3100], 1615);
}
How can I run such async method in background? so that once port forward successful then I can continue to another test.
Exception:
https://gist.github.com/gittadesushil/bc3bf008b7a4fc62c33e97ab1fbf687f
I assume the method PortForward should be rewritten to be asynchronous in the following way:
public async Task<bool> PortForward(string podName, int[] originalPort, int forwardPort)
{
return await Task.Run(() => ForwardPortOperation(podName, originalPort, forwardPort));
}
After that you can write a NUnit test:
[Test]
public async Task VerifyPortForward()
{
var pod = new Pod(_config);
var result = await pod.PortForward("web_service_application", new int[3100], 1615);
// TODO: assert the result
}

C# - What's the best way to use TcpListener (async)

I would create a tcp server with TcpListener, but I don't know what's the best solution to do that.
I tried with 3 examples. See below.
Example 1
(I used BeginAcceptTcpClient)
class Program
{
static void Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
AcceptTcpClient(listener);
while (true)
{
}
}
public static void AcceptTcpClient(TcpListener listener)
{
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
public static void ClientConnected(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
AcceptTcpClient(listener);
DoAsync(client);
}
}
Example 2
(I used BeginAcceptTcpClient with AutoResetEvent)
class Program1
{
private static readonly AutoResetEvent CONNECTION_WAIT_HANDLE = new AutoResetEvent(false);
static void Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
while (true)
{
listener.BeginAcceptTcpClient(ClientConnectedHandle, listener);
CONNECTION_WAIT_HANDLE.WaitOne();
CONNECTION_WAIT_HANDLE.Reset();
}
}
public static void ClientConnectedHandle(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
CONNECTION_WAIT_HANDLE.Set();
DoAsync(client);
}
}
Example 3
(I used AcceptTcpClientAsync)
class Program2
{
static async Task Main(string[] args)
{
var endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4567);
var listener = new TcpListener(endPoint);
listener.Start();
while (true)
{
var client = await listener.AcceptTcpClientAsync();
DoAsync(client);
}
}
public static void AcceptTcpClient(TcpListener listener)
{
listener.BeginAcceptTcpClient(ClientConnected, listener);
}
public static void ClientConnected(IAsyncResult asyncResult)
{
var listener = (TcpListener)asyncResult.AsyncState;
var client = listener.EndAcceptTcpClient(asyncResult);
AcceptTcpClient(listener);
DoAsync(client);
}
}
I think the best solution is the last (Example 3) but I'm not sure. What do you think of that?
This is the code that I'm using in my project. It's a receive only asynchronous server but you can modify it to your liking according to your needs in Task.Run(). I have commented out the code so that you can understand how it works.
static async Task Main(string[] args)
{
await RunServer();
}
static async Task RunServer()
{
TcpListener Listener = new TcpListener(IPAddress.Any, YOURPORTHERE); // Set your listener
Listener.Start(); // Start your listener
while (true) // Permanent loop, it may not be the best solution
{
TcpClient Client = await Listener.AcceptTcpClientAsync(); // Waiting for a connection
_ = Task.Run(() => { // Connection opened. Queues the specified job to run in the ThreadPool, meanwhile the server is ready to accept other connections in parallel
try
{
var Stream = Client.GetStream(); // (read-only) get data bytes
if (Stream.CanRead) // Verify if the stream can be read.
{
byte[] Buffer = new byte[Client.ReceiveBufferSize]; // Initialize a new empty byte array with the data length.
StringBuilder SB = new StringBuilder();
do // Start converting bytes to string
{
int BytesReaded = Stream.Read(Buffer, 0, Buffer.Length);
SB.AppendFormat("{0}", Encoding.ASCII.GetString(Buffer, 0, BytesReaded));
} while (Stream.DataAvailable); // Until stream data is available
if (SB != null) // Stream data is ready and converted to string
// Do some stuffs
}
}
catch (Exception Ex) // In case of errors catch it to avoid the app crash
{
ConsoleMessage.Error(Ex.ToString()); // Detailed exception
}
});
}
}

c# sockets handling multiple clients

I have the following code which I want to implement as my server. As I understand it is async. and should allow connections from multiple clients...
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (true)
{
IAsyncResult res = listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
connectionWaitHandle.WaitOne();
}
}
private void HandleAsyncConnection(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
connectionWaitHandle.Set();
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
I have a test app which simply fires requests to my server. As you can see in the code the server just replies with its date/time. The test app sends say 20 requests which are simply test strings. For each of these requests it opens a socket, sends the data to my server and then closes the socket again.
This works fine with one test app running. However, if I open two test apps the second one cannot connect to the server. I thought because I am handling the request async. and because my test app opens then closes the socket before each call I could handle requests from multiple clients?
Edit
If using >=.Net4.5, it's better to use the new network methods that then permit the adoption of async and await. As such, it might be better to follow the example I provided in this post as a starting point.
Original Post
The following code demonstrates how to accept multiple clients asynchronously without spinning off a new thread per connection.
private TcpListener listener;
public void Start()
{
listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
StartAccept();
}
private void StartAccept()
{
listener.BeginAcceptTcpClient(HandleAsyncConnection, listener);
}
private void HandleAsyncConnection(IAsyncResult res)
{
StartAccept(); //listen for new connections again
TcpClient client = listener.EndAcceptTcpClient(res);
//proceed
}
You can use this pattern for most async operations.
The way you did it, there is no benefit compared to using AcceptTcpClient. Simply loop and create a new thread for each accepted connection:
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
while (canRun)
{
var client = listener.AcceptTcpClient();
new Thread(ClientThread).Start(client);
}
}
private void ClientThread(IAsyncResult res)
{
TcpClient client = (TcpClient)res.AsyncState;
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}
A golden rule when using asynchronous methods is to NOT block the operation. Blocking would defeat the purpose of using async ops.
public void Start()
{
TcpListener listener = new TcpListener(IPAddress.Any, 10250);
listener.Start();
Console.WriteLine("Listening...");
listener.BeginAcceptTcpClient(OnAccept, listener);
}
private void OnAccept(IAsyncResult res)
{
TcpListener listener = (TcpListener)res.AsyncState;
TcpClient client = listener.EndAcceptTcpClient(res);
StringBuilder sb = new StringBuilder();
var data = new byte[client.ReceiveBufferSize];
using (NetworkStream ns = client.GetStream())
{
// Test reply
Byte[] replyData = System.Text.Encoding.ASCII.GetBytes(DateTime.Now.ToString());
ns.Write(replyData, 0, replyData.Length);
ns.Flush();
ns.Close();
}
client.Close();
}

Categories