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);
}
}
Related
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();
}
}
I am working my way trough socket tutorials and I am running in to a problem. I have 3 classes; Server, ServerClient and Client. The Server listens for connections requests, the ServerClient is the server side Socket wrapper and the Client is a user side program trying to connect.
The problem I am facing, is that when the Server passes the accepted socket to the ServerClient class the Socket is disconnected. If I debug the Socket passed has Connected = True, but when I set the local variable in ServerClient it becomes Connected = False.
On the Client side I am not facing problems yet know to me, that Socket remains Connected.
What am I doing wrong, and what else sucks about my code?
Server:
public async void Run()
{
//
if (AcceptingClients)
{
// Error already running
return;
}
//
LoadSettings();
//
IPEndPoint localEndPoint = new IPEndPoint(_settings.Ip, _settings.Port);
// Start The Server
_server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
_server.Bind(localEndPoint);
_server.Listen(100);
//
AcceptingClients = true;
//
OnServerStart(EventArgs.Empty);
// Running => Accept connections
await AcceptConnections();
// Stopped => Close connections
await CloseConnections();
// Server Stopped => Finish stuff
//
OnServerStop(EventArgs.Empty);
}
private async Task AcceptConnections()
{
await Task.Run(() =>
{
while (AcceptingClients)
{
try
{
// Set the _acceptConnectionDone to nonsignaled state.
_acceptConnectionDone.Reset();
//
_server.BeginAccept(AcceptConnectionsCallback, _server);
// Wait until a connection is made before continuing.
_acceptConnectionDone.WaitOne();
}
catch
{
//
}
}
});
}
private static void AcceptConnectionsCallback(IAsyncResult ar)
{
// Signal the AcceptConnections Task to continue.
_acceptConnectionDone.Set();
//
if (!AcceptingClients)
{
// Server Stopping or stopped
return;
}
// Get the socket that handles the client request.
Socket server = (Socket)ar.AsyncState;
Socket client = server.EndAccept(ar);
// Create the client object.
ServerClient newclient = new ServerClient(client);
// Add Events
//
_connections.TryAdd(_totalConnectionCount++, newclient);
}
ServerClient:
private readonly Socket _connection;
//
public ServerClient(Socket s)
{
//
_connection = s;
//
Run();
// Disconnected or needs to be disconnected => Process
Disconnect();
return;
}
private async void Run()
{
//
if (_connection.Connected)
{
//
_connection.ReceiveBufferSize = ServerExt.ReadBufferSize;
_connection.SendBufferSize = ServerExt.SendBufferSize;
_connection.NoDelay = true;
//
await ListenToClient();
}
}
Client:
public async void Connect()
{
if (_connection != null)
{
// Check if we are not connected already
}
//
LoadSettings();
//
try
{
//
IPEndPoint remoteEndPoint = new IPEndPoint(_settings.Ip, _settings.Port);
// Create a TCP/IP socket.
_connection = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)
{
ReceiveBufferSize = ServerExt.ReadBufferSize,
SendBufferSize = ServerExt.SendBufferSize,
NoDelay = true
};
// Connect to the remote endpoint.
_connection.Connect(remoteEndPoint);
//
if (_connection.Connected)
{
//
await ListenToServer();
}
}
catch
{
//
}
// Disconnected or needs to be disconnected => Process
Disconnect();
return;
}
Thnx.
I managed to keep the connection open by changing the code for ServerClient.
public ServerClient(int id, Socket s, ClientConnectedDelegate connected, ClientDisconnectedDelegate disconnected)
{
//
Id = id;
//
_connection = s;
_disconnected = disconnected;
//
Ip = _connection.RemoteIp();
//
_connection.ReceiveBufferSize = ServerExt.ReadBufferSize;
_connection.SendBufferSize = ServerExt.SendBufferSize;
_connection.NoDelay = true;
//
_netStream = new NetworkStream(_connection, FileAccess.ReadWrite);
//
if (_cert != null)
{
_ssl = new SslStream(_netStream, false);
_ssl.AuthenticateAsServer(_cert, false, SslProtocols.Tls, true);
//
_br = new BinaryReader(_ssl, Encoding.UTF8, false);
_bw = new BinaryWriter(_ssl, Encoding.UTF8, false);
}
else
{
_br = new BinaryReader(_netStream, Encoding.UTF8, false);
_bw = new BinaryWriter(_netStream, Encoding.UTF8, false);
}
//
Task.Factory.StartNew(ListenToClient);
//
connected(this);
}
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);
}
}
}
I have to connect, send and receive socket messages to a server. I have to implement the client application which is based on Windows Forms. (Target Framework: 4.5.1)
In five minute intervals I have to send a message to the server to keep the server online. (This is not a keep alive ping, this is a specified command to the server.)
I'd like to implement this task to keep the GUI live (not blocked), until the socket communication working in the background.
Everything is working fine, until one or more of the server are not available. The ConnectTaskAsync method wait (approximately 15 seconds) and send a "TIME OUT EXCEPTION". But this time to exception raised is a long time.
How is possible to call connect socket with 5 seconds timeout without blocking UI thread?
On Form load event, I create a timer
private void Form1_Load(object sender, EventArgs e)
{
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 1000;
t.Tick += this.displayTimers;
t.Start();
System.Windows.Forms.Timer tKeepAlive = new System.Windows.Forms.Timer();
tKeepAlive.Interval = 10000;
tKeepAlive.Tick += clsKeepAlive.keepAlivePanelTimer;
tKeepAlive.Start();
}
keepAlivePanelTimer is caller by timer
public async static void keepAlivePanelTimer(object sender, EventArgs e)
{
List<clsPanelItem> panelList = (List<clsPanelItem>)((clsVmsGroup)actGroup).lstVmsItems;
IEnumerator _idePanel = panelList.GetEnumerator();
while (_idePanel.MoveNext())
{
clsPanelItem actPanel = (clsPanelItem)_idePanel.Current;
try
{
//CancellationTokenSource cts = new CancellationTokenSource();
await keepAlivePanel(actPanel);
}
catch (Exception _ex)
{
//Timeout Exceptions are handle here
System.Diagnostics.Debug.Print("Err: " + _ex.Message + " - Panel: " + actPanel.ipAddress.ToString());
}
finally
{
}
}
}
keepAlivePanel Async task called from timer
private static async Task keepAlivePanel(clsPanelItem actPanel, CancellationToken ct)
{
IPAddress ipAddress = actPanel.ipAddress;
IPEndPoint remoteEP = new IPEndPoint(ipAddress, app.vmsPanelCommPort);
// Create a TCP/IP socket.
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.SendTimeout = 1000; //Nothing was happened
client.ReceiveTimeout = 1000; //Nothing was happened
await async45.ConnectTaskAsync(client, remoteEP, ipAddress, app.vmsPanelCommPort, ct);
}
ConnectTaskAsync connect to server
public static class async45
{
public static Task ConnectTaskAsync(Socket socket, EndPoint endpoint, IPAddress ip, int port, CancellationToken ct)
{
Task t = Task.Factory.FromAsync(socket.BeginConnect, socket.EndConnect, endpoint, null);
return t;
}
}
Another methods to use send and receive bytes
public static Task SendTaskAsync(this Socket socket, byte[] buffer)
{
return Task.Factory.FromAsync<int>(
socket.BeginSend(buffer, 0, buffer.Length, SocketFlags.None, null, socket),
socket.EndSend);
}
public static Task<int> ReceiveTaskAsync(this Socket socket, byte[] buffer, int offset, int count)
{
return Task.Factory.FromAsync<int>(
socket.BeginReceive(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndReceive);
}
I tried different things with less success.
// var timeoutTask = Task.Delay(TimeSpan.FromSeconds(2));
// //var ConnectTask = Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, remoteEP, null, TaskCreationOptions.LongRunning);
// var ConnectTask = Task.Factory.FromAsync(client.BeginConnect, client.EndConnect, remoteEP, null);
// var completedTask = await Task.WhenAny(timeoutTask, ConnectTask)
// .ConfigureAwait(false);
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.