I have async tcp server that can accept multiple clients at the same time. The scenarios where client requests data from server are served well. Now I am trying to implement the situation in which server has to find a particular client and send some data to it ie the client is connected but has not requested data but server wants to send some data to it. How can I find the thread that is already running between the server and client and place data on it?
Here is server code:
public async void RunServerAsync()
{
tcpListener.Start();
while (true)
{
try
{
var client = await tcpListener.AcceptTcpClientAsync();
Accept(client);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
private async void Accept(TcpClient client)
{
//get client information
String clientEndPoint = client.Client.RemoteEndPoint.ToString();
Console.WriteLine("Client connected at " + clientEndPoint );
await Task.Yield ();
try
{
using (client)
using (NetworkStream stream = client.GetStream())
{
byte[] dataReceived = new byte[100];
while (true) //read input stream
{
try
{
int x = await stream.ReadAsync(dataReceived, 0, dataReceived.Length);
if (x != 0)
{
//pass on data for processing
byte[] dataToSend = await ProcessData(dataReceived);
//send response,if any, to the client
if (dataToSend != null)
{
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
ConsoleMessages.DisplayDataSent(dataReceived, dataToSend);
}
}
}
catch (ObjectDisposedException)
{
stream.Close();
}
}
}
} //end try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}//end Accept(TcpClient client)
You need to keep track of your clients. For example:
ConcurrentDictionary<Guid, TcpClient> _clients = new ConcurrentDictionary<Guid, TcpClient>();
public async void RunServerAsync()
{
tcpListener.Start();
while (true)
{
try
{
var client = await tcpListener.AcceptTcpClientAsync();
var clientId = Guid.NewGuid();
Accept(clientId, client);
_clients.TryAdd(clientId, client);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
public Task SendAsync(Guid clientId, Byte[] buffer, Int32 offset, Int32 count)
{
TcpClient client;
if (_clients.TryGetValue(clientId, out client))
return client.GetStream().WriteAsync(buffer, offset, count);
// client disconnected, throw exception or just ignore
return Task.FromResult<Object>(null);
}
public Boolean TryGetClient(Guid clientId, out TcpClient client)
{
return _clients.TryGetValue(clientId, out client);
}
private async void Accept(Guid clientId, TcpClient client)
{
//get client information
String clientEndPoint = client.Client.RemoteEndPoint.ToString();
Console.WriteLine("Client connected at " + clientEndPoint);
await Task.Yield();
try
{
using (client)
using (NetworkStream stream = client.GetStream())
{
byte[] dataReceived = new byte[100];
while (true) //read input stream
{
try
{
int x = await stream.ReadAsync(dataReceived, 0, dataReceived.Length);
if (x != 0)
{
//pass on data for processing
byte[] dataToSend = await ProcessData(dataReceived);
//send response,if any, to the client
if (dataToSend != null)
{
await stream.WriteAsync(dataToSend, 0, dataToSend.Length);
ConsoleMessages.DisplayDataSent(dataReceived, dataToSend);
}
}
}
catch (ObjectDisposedException)
{
stream.Close();
}
}
}
} //end try
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
finally
{
// deregister client
_clients.TryRemove(clientId, out client);
}
}//end Accept(TcpClient client)
TCP is bi-directional, so either side can send data whenever they want.
What you need to do is store a reference to the TcpClient on Accept, something like:
//Class Level
List<TcpClient> connectedClients = List<TcpClient>();
private async void Accept(TcpClient client)
{
connectedClients.Add(client);
...
}
public SendMessage(int index, String message)
{
//pseudo-code
connectedClients[index].Send(message);
}
Normally I will raise an event on connect so whoever is using the class can get the new client's index. The send message code is pseudo-code, there are good examples on MSDN of how to actually perform the send.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.