在之前的代码中,我们了解了如何开发异步客户端Socket,现在开发异步服务端Socket就轻松了
首先我们还是先查看一下微软官方文档的API了解下面的几个方法:
1、Socket.BeginAccept()
2、Socket.EndAccept()
3、Socket.BeginReceive()
4、Socket.EndReceive()
5、Socket.BeginSend()
6、SocketEndSend()
参考连接:Socket 类 (System.Net.Sockets) | Microsoft Learn
我们还需要一个存客户端信息的类ClientState,目前里面只需要一个客户端Socket和一个缓冲区数组
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
#nullable disable
namespace UnityServer
{
internal class ClientState
{
/// <summary>
/// 客户端socket
/// </summary>
public Socket socket;
/// <summary>
/// 接收缓冲区
/// </summary>
public byte[] readBuff=new byte[1024];
}
}
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
#nullable disable
namespace UnityServer
{
internal class Server
{
static string receiveStr = "";
/// <summary>
/// 服务端socke
/// </summary>
static Socket serverSocket;
/// <summary>
/// 客户端socket以及客户端信息的字典
/// </summary>
static Dictionary<Socket, ClientState> clients = new Dictionary<Socket, ClientState>();
public static void Main()
{
//定义socket
serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
//绑定ip和端口
IPAddress ip = IPAddress.Parse("127.0.0.1");
IPEndPoint iPEndPoint = new IPEndPoint(ip, 8888);
serverSocket.Bind(iPEndPoint);
//监听
serverSocket.Listen(0);
Console.WriteLine("服务端启动成功");
serverSocket.BeginAccept(AcceptCallback, serverSocket);
Console.ReadLine();
}
/// <summary>
/// 应答回调
/// </summary>
/// <param name="ar"></param>
private static void AcceptCallback(IAsyncResult ar)
{
try
{
Socket serverSocket = ar.AsyncState as Socket;
Socket clientSocket = serverSocket.EndAccept(ar);
//创建客户端的ClientState以及添加字典
ClientState state = new ClientState();
state.socket = clientSocket;
clients.Add(clientSocket, state);
Console.WriteLine("有一个客户端Accept");
clientSocket.BeginReceive(state.readBuff, 0, 1024, 0, ReceiveCallback, state);
serverSocket.BeginAccept(AcceptCallback, serverSocket);
}
catch (SocketException ex)
{
Console.WriteLine("应答失败" + ex.ToString());
}
}
/// <summary>
/// 接收回调
/// </summary>
/// <param name="ar"></param>
private static void ReceiveCallback(IAsyncResult ar)
{
try
{
ClientState state = ar.AsyncState as ClientState;
Socket clientSocket = state.socket;
int count = clientSocket.EndReceive(ar);
//客户端的关闭
if (count == 0)
{
clientSocket.Close();
clients.Remove(clientSocket);
Console.WriteLine("客户端断开连接");
return;
}
receiveStr = Encoding.UTF8.GetString(state.readBuff, 0, count);
Console.WriteLine(receiveStr);
foreach (ClientState s in clients.Values)
{
s.socket.BeginSend(Encoding.UTF8.GetBytes(receiveStr), 0, receiveStr.Length, 0, SendCallback, clientSocket);
}
clientSocket.BeginReceive(state.readBuff, 0, 1024, 0, ReceiveCallback, state);
}
catch (SocketException ex)
{
Console.WriteLine("接收失败" + ex.ToString());
}
}
/// <summary>
/// 发送回调
/// </summary>
/// <param name="ar"></param>
private static void SendCallback(IAsyncResult ar)
{
try
{
Socket clientSocket = ar.AsyncState as Socket;
clientSocket.EndSend(ar);
}
catch (SocketException ex)
{
Console.WriteLine("发送失败" + ex.ToString());
}
}
}
}
这里用字典来储存客户端信息以及对应Socket,后面的基本逻辑和之前同步的一样,只不过都改成异步方法
这里面为了实现给多个客户端发送,我们遍历字典里面所有客户端就可以了
注意:这里面结尾的Console.ReadLine(),因为我们是异步接收,是子线程进行,如果没有这句话,主线程会直接结束