没研究太深,仅仅是接收客户端连接和读数据。
服务器,所有异步方法会自动放到后台线程池去处理,无需我们代码去创建线程:
internal class ClientMessage
{
public ClientMessage(TcpClient client,int buffSize)
{
Client = client;
Data = new byte[buffSize];
}
public TcpClient Client { get; set; }
public byte[] Data { get;set;}
}
public class TcpServer
{
private readonly ConcurrentDictionary<string, TcpClient> _clients = new ConcurrentDictionary<string, TcpClient>();
private readonly List<string> _failedClientKey = new List<string>();
TcpListener _tcpListener;
/// <summary>
/// 处理连接请求
/// </summary>
/// <param name="result"></param>
void AsyncAccept(IAsyncResult result)
{
//透穿参数监听器,就是成员_tcpListener
var tcpListener = (TcpListener)result.AsyncState;
//得到客户端
var client = tcpListener.EndAcceptTcpClient(result);
Console.WriteLine("A client connected:" + client.Client.RemoteEndPoint.ToString());
var msg = new ClientMessage(client, client.ReceiveBufferSize);
//去异步读数据
ReadFromClient(msg);
_clients.TryAdd(client.Client.RemoteEndPoint.ToString(), client);
//异步接受下一个请求
Accept();
}
void AsyncRead(IAsyncResult result)
{
var msg = result.AsyncState as ClientMessage;
try
{
var len = msg.Client.Client.EndReceive(result);
var message = Encoding.ASCII.GetString(msg.Data, 0, len);
Console.WriteLine("Received:" + message);
//读下一次的数据
ReadFromClient(msg);
}
catch(SocketException e)
{
//客户端关闭
Console.WriteLine(e.Message + ":" + msg.Client.Client.RemoteEndPoint);
_clients.TryRemove(msg.Client.Client.RemoteEndPoint.ToString(),out var client);
client.Close();
}
}
void ReadFromClient(ClientMessage msg)
{
var result = msg.Client.Client.BeginReceive(
msg.Data, 0, msg.Data.Length,
SocketFlags.None, AsyncRead, msg);
}
public void Accept()
{
//异步接收客户端连接
var result = _tcpListener.BeginAcceptTcpClient(AsyncAccept, _tcpListener);
}
public void Start(int port)
{
_tcpListener = new TcpListener(IPAddress.Any, port);
_tcpListener.Start(10);
Accept();
}
void AsyncSend(IAsyncResult result)
{
var client = result.AsyncState as TcpClient;
var num = client?.Client.EndSend(result);
if (num.HasValue)
{
Console.WriteLine("sent data bytes:" + num);
}
}
public void Send(string msg)
{
var data = Encoding.ASCII.GetBytes(msg);
foreach (var client in _clients)
{
try
{
var result = client.Value.Client.BeginSend(data, 0, data.Length, SocketFlags.None,
AsyncSend, client.Value);
}
catch (SocketException e)
{
Console.WriteLine(e.Message + ":" + client.Key);
client.Value.Close();
_failedClientKey.Add(client.Key);
}
}
if (_failedClientKey.Any())
{
foreach (var key in _failedClientKey)
{
_clients.TryRemove(key,out _);
}
_failedClientKey.Clear();
}
}
}
class Program
{
static void Main(string[] args)
{
var tcpServer = new TcpServer();
try
{
tcpServer.Start(args.Length > 1 ? int.Parse(args[1]) : 13000);
Console.WriteLine("server start");
}
catch(Exception e)
{
Console.WriteLine("server start failed");
}
while (true)
{
var str = Console.ReadLine();
if (string.Compare(str, "exit") != 0)
{
tcpServer.Send(str);
}
else
{
break;
}
}
}
}
测试用的客户端:
public class MyTcpClient
{
private readonly TcpClient _client = new TcpClient();
private byte[] _data;
public void Start(string ip, int port)
{
_client.Connect(new IPEndPoint(IPAddress.Parse("127.0.0.1"), 13000));
_data = new byte[_client.ReceiveBufferSize];
Receive();
}
void Receive()
{
_client.Client.BeginReceive(_data, 0, _data.Length, SocketFlags.None, AsyncReceive, null);
}
void AsyncReceive(IAsyncResult result)
{
try
{
var num = _client.Client.EndReceive(result);
var message = Encoding.ASCII.GetString(_data, 0, num);
Console.WriteLine("Received:" + message);
Receive();
}
catch (SocketException e)
{
Console.WriteLine(e);
_client.Close();
}
}
void AsyncSend(IAsyncResult result)
{
var client = result.AsyncState as TcpClient;
var num = client?.Client.EndSend(result);
if (num.HasValue)
{
Console.WriteLine("sent data bytes:" + num);
}
}
public void Send(string msg)
{
var data = Encoding.ASCII.GetBytes(msg);
try
{
var result = _client.Client.BeginSend(data, 0, data.Length, SocketFlags.None,
AsyncSend, _client);
}
catch (SocketException e)
{
Console.WriteLine(e);
_client.Close();
}
}
}
class Program
{
static void Main(string[] args)
{
var client = new MyTcpClient();
try
{
client.Start("127.0.0.1", 13000);
Console.WriteLine("connected");
while (true)
{
var str = Console.ReadLine();
if (string.Compare(str, "exit") != 0)
{
client.Send(str);
}
else
{
break;
}
}
}
catch(Exception e)
{
Console.WriteLine(e.Message);
}
}
}