это, вероятно, не идеально, но я нахожусь в той же ситуации, что и вы, и создал Async TCP Client / Server для практики и экспериментов.
Ниже приведен фрагмент моей реализации, он работает с
Сервер:
public class AsyncServerDemo
{
private CancellationTokenSource cancel;
private readonly TcpListenerEx listener;
private Task WaitingForConnections;
private Timer timerCallAcceptClients;
public bool IsRunning { get; private set; }
public AsyncServerDemo(int port)
{
cancel = new CancellationTokenSource();
listener = new TcpListenerEx(IPAddress.Any, port);
}
private Task<string> WaitForMessageAsync(TcpClient client, CancellationToken token)
{
return Task.Run(() =>
{
StringBuilder sb = new StringBuilder();
bool dataAvailable = false;
while (!token.IsCancellationRequested)
{
while (client.Client.Available > 0)
{
dataAvailable = true;
int buffered = client.Client.Available;
byte[] buffer = new byte[buffered];
client.Client.Receive(buffer);
sb.Append(Encoding.ASCII.GetString(buffer));
}
if (dataAvailable)
{
dataAvailable = false;
return sb.ToString();
}
};
return string.Empty; //timeout
});
}
private Task AcceptClientAsync()
{
return Task.Factory.StartNew(async () =>
{
IsRunning = true && !cancel.IsCancellationRequested;
while (!cancel.IsCancellationRequested)
{
if (!listener.Pending())
{
continue;
}
TcpClient newClient = await listener.AcceptTcpClientAsync().ConfigureAwait(false);
Stopwatch timeout = new Stopwatch();
timeout.Restart();
string message = await WaitForMessageAsync(newClient, new CancellationTokenSource(TimeSpan.FromSeconds(5)).Token);
if (message != null)
{
//TODO: Message recieved
}
timeout.Stop();
}
});
}
public void Start()
{
listener.Start();
timerCallAcceptClients = new Timer(new TimerCallback((state) =>
{
AcceptClientAsync();
}), null, 0, (int)TimeSpan.FromSeconds(1).TotalMilliseconds);
}
public async void Stop()
{
if (!IsRunning) return;
using (cancel)
cancel.Cancel();
timerCallAcceptClients.Dispose();
if (WaitingForConnections != null)
await WaitingForConnections;
cancel = null;
listener.Stop();
IsRunning = false;
cancel = new CancellationTokenSource();
}
}
Клиент:
public class ClientExDemo
{
private Task<string> WaitForMessage;
private NetworkStream currentStream;
private CancellationTokenSource messageToken;
public EventHandler<ClientEx> OnServerFound;
public TcpClient Connection;
public EventHandler<string> OnMessage;
public async Task StartListenAsync(CancellationTokenSource token = null)
{
if (token == null)
messageToken = new CancellationTokenSource();
else
messageToken = token;
currentStream = Connection.GetStream();
string message = "";
if (message.Length > 0)
OnMessage?.Invoke(this, message);
if (!messageToken.IsCancellationRequested)
{
await StartListenAsync(token);
}
Timeout();
}
protected virtual void Timeout()
{
}
public async Task WaitForServerAsync(string ip, int port)
{
do
{
try
{
await Connection.ConnectAsync(ip, port);
}
catch (SocketException x)
{
}
await Task.Delay(50);
} while (!Connection.Connected);
}
public void StopListen()
{
using (messageToken)
{
messageToken.Cancel();
}
try
{
WaitForMessage.GetAwaiter().GetResult();
}
catch (AggregateException)
{
}
currentStream.Close();
messageToken = null;
currentStream = null;
WaitForMessage = null;
}
public ClientExDemo()
{
Connection = new TcpClient();
OnServerFound += ServerFound;
}
private void ServerFound(object sender, ClientEx args)
{
}
public void Send(string message)
{
Connection.Client.Send(Encoding.ASCII.GetBytes(message));
}
}
Вы можете отправлять сообщения с клиента в простом консольном приложении:
ClientEx client= new ClientEx();
await client.WaitForServerAsync(ip, port);
string msg = string.Empty;
do
{
Console.Write("Send Message: ");
msg = Console.ReadLine();
shell.Send(msg);
} while (msg != "q");
Console.WriteLine();
Console.WriteLine("BYE");
Console.ReadKey();