Socket简介
      Socket (套接字)是网络编程的基础,在 C# 中通过 System.Net.Sockets 命名空间提供了一套完整的 API 来实现网络通信。
网络上的两个程序通过一个双向的通信连接实现数据交换, 这个连接的一端称为一个Socket。 一个Socket包含了进行网络通信必需的五种信息:连接使用的协议、 本地主机的IP地址、 本地的协议端口、 远程主机的IP地址和远程协议端口。
网络通信流程
服务端
1、注册绑定阶段:服务端初始化一个Socket对象,绑定服务器的IP地址和端口号(使用Bind方法)。
2、开启监听 ,使用Listen方法。
3、等待客户端连接,使用Accept方法。
4、收发数据:成功连接后,可以进行接收数据(使用Receive方法)和发送数据(使用Send方法)。
5、关闭连接,使用Close方法。
客户端
1、注册绑定阶段:客户端初始化一个Socket对象,绑定服务器的IP地址和端口号(使用Bind方法)。
2、连接服务器,使用Connect方法。
3、收发数据:成功连接后,可以进行接收数据(使用Receive方法)和发送数据(使用Send方法)。
4、关闭连接,使用Close方法。
Socket API
常用属性
| API | 说明 | 
| AddressFamily | 指定Socket类的实例可以使用的寻址方案,一般知道以下两个即可: InterNetwork:IPv4地址 nterNetworkV6 :IPv6地址 
 | 
| SocketType | 指定Socket类的实例表示的套接字类型,一般知道以下两个即可: Stream:支持可靠、双向、基于连接的字节流,而不重复数据,也不保留边界。 此类型的 Socket 与单个对方主机通信,并且在通信开始之前需要建立远程主机连接。 Stream 使用传输控制协议 (Tcp) 和  Dgram:支持数据报,即最大长度固定(通常很小)的无连接、不可靠消息。 消息可能会丢失或重复并可能在到达时不按顺序排列。 Socket 类型的 Dgram 在发送和接收数据之前不需要任何连接,并且可以与多个对方主机进行通信。 Dgram 使用 Datagram 协议 (Udp) 和  | 
| ProtocolType | 指定Socket类支持的协议b一般知道以下两个即可: Tcp:传输控制协议 Udp:用户数据报协议 | 
| Available | 获取已经从网络接收且可供读取的数据量。 
 | 
| Blocking | 
 | 
| Connected | 如果 Socket 在最近操作时连接到远程资源,则为 true;否则为 false。 | 
| IsBound | 
 | 
| SendBufferSize | 
 | 
| SendTimeout | 
 | 
| ReceiveBufferSize | 
 | 
| ReceiveTimeout | 
 | 
常用方法
| API | 说明 | 
| Bind | 使Socket与一个本地终结点相关联 | 
| Listen | 将Socket置于监听状态 | 
| Close | 关闭Socket连接并释放所有关联的资源 | 
| Shutdown | 禁用某Socket上的发送和接收 | 
| GetSocketOption | 获取Socket选项的值 | 
| SetSocketOption | 设置Socket选项 | 
| Poll | 确定Socket状态 | 
同步方法
均为阻塞方法,程序会卡住直到成功响应
| API | 说明 | 
| Connect | 建立与远端主机的连接 | 
| Accept | 为新建连接创建新的Socket | 
| Send | 发送数据 | 
| Receive | 接收数据 | 
| Disconnect | 关闭套接字连接并允许重用套接字 | 
异步方法
与同步方法不同的是,异步方法不会阻塞线程。
只有在主线程中才能操作UI组件,由于异步回调是在其他线程执行的。可以通过缓存接收数据,再在Update中进行读取并传递给UI组件。
两种异步方式说明
在 C# 中,xxxAsync 和 Beginxxx/Endxxx 都是用于异步网络通信的方法,但它们属于不同的异步编程模型。
xxxAsync
ReceiveAsync 是 .NET Framework 4.5+ 和 .NET Core/.NET 5+ 引入的现代异步方法,基于 Task 的异步模式(TAP),适合 async/await 编程。
适用场景
-  推荐在新项目中使用,代码更简洁,可读性更好。 
-  适用于 .NET Core / .NET 5+ 和 .NET Framework 4.5+。 
-  配合 async/await使用,避免回调地狱。
特点
1、简洁:直接 await 等待数据,无需回调。
 2、可取消:可配合 CancellationToken 使用。
 3、现代推荐:适用于新代码。
Beginxxx / Endxxx
BeginReceive 和 EndReceive 是 .NET 早期的异步编程模型(APM,Asynchronous Programming Model),基于 IAsyncResult 和回调机制。
适用场景
-  旧版 .NET Framework(4.0 及以下) 兼容代码。 
-  需要手动管理 IAsyncResult和回调。
特点
1、回调模式:需要手动处理 IAsyncResult 和回调函数。
 2、较旧 API:不推荐在新代码中使用,除非维护旧项目。
 3、无 async/await 支持:代码结构可能更复杂。
对比总结
| 特性 | ReceiveAsync(TAP) | BeginReceive/EndReceive(APM) | 
|---|---|---|
| 编程模型 | async/await(推荐) | 回调模式( IAsyncResult) | 
| 代码可读性 | 高(线性执行) | 低(嵌套回调) | 
| 适用版本 | .NET 4.5+, .NET Core | .NET Framework 所有版本 | 
| 取消支持 | 支持 ( CancellationToken) | 不支持 | 
| 推荐使用场景 | 新项目、现代异步代码 | 旧代码维护 | 
如何选择?
-  新项目 ➔ ReceiveAsync+async/await(代码更清晰,维护方便)。
-  旧项目维护 ➔ BeginReceive/EndReceive(兼容旧版 .NET)。
-  高性能场景 ➔ 也可以考虑 SocketAsyncEventArgs(更低级别的异步模型)。
结论
-  优先使用 ReceiveAsync(现代、简洁、可取消)。
-  仅在旧代码中保留 BeginReceive/EndReceive(兼容性需求)。
Beginxxx/Endxxx
| API | 说明 | 
| BeginConnect | 开启一个与远端主机的连接的异步请求 | 
| EndConnect | 结束挂起的异步连接请求 | 
| BeginAccept | 开始一个异步操作来接受一个传入的连接尝试 | 
| EndAccept | 异步接受传入的连接尝试 | 
| BeginSend | 将数据异步发送到连接的 Socket | 
| EndSend | 结束挂起的异步发送 | 
| BeginReceive | 开始从连接的 Socket 中异步接收数据 | 
| EndReceive | 结束挂起的异步读取 | 
| BeginDisconnect | 开始异步请求从远程终结点断开连接 | 
| EndDisconnect | 结束挂起的异步断开连接请求 | 
BeginConnect/EndConnect
用于客户端异步连接服务服务端
public void ConnectToServer(string host, int port)
{
    Socket clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    
    // 开始异步连接
    clientSocket.BeginConnect(host, port, ConnectCallback, clientSocket);
}
private void ConnectCallback(IAsyncResult ar)
{
    try
    {
        Socket clientSocket = (Socket)ar.AsyncState;
        
        // 完成连接操作
        clientSocket.EndConnect(ar);
        Console.WriteLine("Connected to server");
        
        // 连接成功后开始接收数据
        StartReceiving(clientSocket);
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Connection failed: {ex.SocketErrorCode}");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Connection error: {ex.Message}");
    }
}BeginAccept/EndAccept
用于服务端异步接受客户端连入
public void StartServer(int port)
{
    Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
    listener.Bind(new IPEndPoint(IPAddress.Any, port));
    listener.Listen(100);
    
    // 开始异步接受连接
    listener.BeginAccept(AcceptCallback, listener);
}
private void AcceptCallback(IAsyncResult ar)
{
    Socket listener = (Socket)ar.AsyncState;
    
    try
    {
        // 完成接受连接操作
        Socket clientSocket = listener.EndAccept(ar);
        Console.WriteLine($"New connection from {clientSocket.RemoteEndPoint}");
        
        // 开始接收数据
        StartReceiving(clientSocket);
        
        // 继续接受新连接
        listener.BeginAccept(AcceptCallback, listener);
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Accept failed: {ex.SocketErrorCode}");
    }
    catch (ObjectDisposedException)
    {
        // 监听器已关闭
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Accept error: {ex.Message}");
    }
}BeginSend/EndSend
用于客户端/服务端异步发送数据
public void SendData(Socket socket, byte[] data)
{
    try
    {
        // 开始异步发送
        socket.BeginSend(data, 0, data.Length, SocketFlags.None, SendCallback, socket);
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Send error: {ex.SocketErrorCode}");
        socket.Close();
    }
}
private void SendCallback(IAsyncResult ar)
{
    Socket socket = (Socket)ar.AsyncState;
    
    try
    {
        // 完成发送操作
        int bytesSent = socket.EndSend(ar);
        Console.WriteLine($"Sent {bytesSent} bytes");
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Send completion error: {ex.SocketErrorCode}");
        socket.Close();
    }
    catch (ObjectDisposedException)
    {
        // Socket已关闭
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Send error: {ex.Message}");
        socket.Close();
    }
}BeginReceive/EndReceive
用于客户端/服务端异步接收数据
private void StartReceiving(Socket socket)
{
    byte[] buffer = new byte[8192];
    
    try
    {
        // 开始异步接收
        socket.BeginReceive(buffer, 0, buffer.Length, SocketFlags.None, ReceiveCallback, 
            new ReceiveState { Socket = socket, Buffer = buffer });
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Receive error: {ex.SocketErrorCode}");
        socket.Close();
    }
}
private void ReceiveCallback(IAsyncResult ar)
{
    ReceiveState state = (ReceiveState)ar.AsyncState;
    Socket socket = state.Socket;
    
    try
    {
        // 完成接收操作
        int bytesRead = socket.EndReceive(ar);
        
        if (bytesRead > 0)
        {
            // 处理接收到的数据
            byte[] receivedData = new byte[bytesRead];
            Array.Copy(state.Buffer, 0, receivedData, 0, bytesRead);
            Console.WriteLine($"Received: {Encoding.UTF8.GetString(receivedData)}");
            
            // 继续接收数据
            StartReceiving(socket);
        }
        else
        {
            // 连接已关闭
            Console.WriteLine("Connection closed by remote host");
            socket.Close();
        }
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Receive error: {ex.SocketErrorCode}");
        socket.Close();
    }
    catch (ObjectDisposedException)
    {
        // Socket已关闭
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Receive error: {ex.Message}");
        socket.Close();
    }
}
// 用于传递状态的辅助类
class ReceiveState
{
    public Socket Socket { get; set; }
    public byte[] Buffer { get; set; }
}BeginDisconnect/EndDisconnect
用于客户端异步断开连接服务端
public void DisconnectSocket(Socket socket)
{
    try
    {
        // 开始异步断开连接
        socket.BeginDisconnect(false, DisconnectCallback, socket);
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Disconnect error: {ex.SocketErrorCode}");
        socket.Close();
    }
}
private void DisconnectCallback(IAsyncResult ar)
{
    Socket socket = (Socket)ar.AsyncState;
    
    try
    {
        // 完成断开连接操作
        socket.EndDisconnect(ar);
        Console.WriteLine("Disconnected successfully");
        socket.Close();
    }
    catch (SocketException ex)
    {
        Console.WriteLine($"Disconnect error: {ex.SocketErrorCode}");
        socket.Close();
    }
    catch (ObjectDisposedException)
    {
        // Socket已关闭
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Disconnect error: {ex.Message}");
        socket.Close();
    }
}xxxAsync
如果异步套接字方法 (xxxAsync) 返回 true,请在Completed 回调中查询完成状态、获取操作结果。如果异步套接字方法 (xxxAsync) 返回 false,则操作同步完成,将不会引发 e 参数的 Completed 事件。 可查询上下文属性获取操作结果。
| API | 说明 | 
| AcceptAsync | 开始一个异步操作来接受一个传入的连接尝试 | 
| ConnectAsync | 开启一个与远端主机的连接的异步请求 | 
| SendAsync | 将数据异步发送到连接的 Socket | 
| ReceiveAsync | 开始从连接的 Socket 中异步接收数据 | 
| DisconnectAsync | 开始异步请求从远程终结点断开连接 | 
SocketAsyncEventArgs
SocketAsyncEventArgs 类通过重用操作上下文和缓冲区来减少内存分配,主要特点包括:
-  重用操作上下文对象 
-  支持缓冲区池 
-  减少异步操作中的内存分配 
-  提供更细粒度的控制 
   通过合理使用 SocketAsyncEventArgs,可以构建出高性能、可扩展的网络应用程序,特别适合需要处理大量并发连接的场景。
关键属性
// 缓冲区相关
public byte[] Buffer { get; }          // 当前使用的缓冲区
public int Offset { get; }             // 缓冲区起始偏移
public int Count { get; }              // 可操作字节数
public int BytesTransferred { get; }   // 已传输字节数
// 连接信息
public EndPoint RemoteEndPoint { get; set; }
public EndPoint LocalEndPoint { get; }
// 操作状态
public SocketError SocketError { get; set; }  // 操作结果
public SocketFlags SocketFlags { get; set; }  // 特殊标志
// 用户自定义数据
public object UserToken { get; set; }  // 用户自定义对象重要方法
// 缓冲区管理
public void SetBuffer(byte[] buffer, int offset, int count);
public void SetBuffer(int offset, int count);
// 内存缓冲区管理
public void SetBuffer(Memory<byte> buffer);  // .NET Core 新增
// 操作结果获取
public Socket AcceptSocket { get; set; }  // 用于Accept操作AcceptAsync
var acceptArgs = new SocketAsyncEventArgs();
acceptArgs.UserToken = acceptSocket;
acceptArgs.Completed += OnAcceptCompleted;
if (!listener.AcceptAsync(acceptArgs))
{
    // 操作同步完成
    OnAcceptCompleted(listener, acceptArgs);
}
private void OnAcceptCompleted(object sender, SocketAsyncEventArgs e)
{
    if (e.SocketError == SocketError.Success)
    {
        Socket clientSocket = e.AcceptSocket;
        Console.WriteLine($"Client connected from: {clientSocket.RemoteEndPoint}");
       
        // 开始接收数据  ReceiveAsync
        // 准备接受下一个连接 AcceptAsync
        e.AcceptSocket = null; // 必须重置
    }
    else
    {
        Console.WriteLine($"Accept error: {e.SocketError}");
    }
}ConnectAsync
var connectArgs = new SocketAsyncEventArgs();
connectArgs.RemoteEndPoint = new DnsEndPoint(host, port);
connectArgs.Completed += OnConnectCompleted;
if (!clientSocket.ConnectAsync(connectArgs))
{
    // 操作同步完成
    OnConnectCompleted(clientSocket, connectArgs);
}
private void OnConnectCompleted(object sender, SocketAsyncEventArgs e)
{
    if (e.SocketError == SocketError.Success)
    {
        Console.WriteLine("Connected to server");
        // 连接成功后可以开始发送或接收数据
        
    }
    else
    {
        Console.WriteLine($"Connection failed: {e.SocketError}");
    }
}SendAsync
public void SendData(Socket socket, byte[] data)
{
    var sendArgs = new SocketAsyncEventArgs();
    sendArgs.SetBuffer(data, 0, data.Length);
    sendArgs.Completed += OnSendCompleted;
    sendArgs.UserToken = socket;
    if (!socket.SendAsync(sendArgs))
    {
        // 操作同步完成
        OnSendCompleted(socket, sendArgs);
    }
}
private void OnSendCompleted(object sender, SocketAsyncEventArgs e)
{
    if (e.SocketError == SocketError.Success)
    {
        Console.WriteLine($"Sent {e.BytesTransferred} bytes");
    }
    else
    {
        Console.WriteLine($"Send error: {e.SocketError}");
    }
}ReceiveAsync
private void StartReceiving(Socket socket)
{
    var receiveArgs = new SocketAsyncEventArgs();
    var buffer = new byte[4096];
    receiveArgs.SetBuffer(buffer, 0, buffer.Length);
    receiveArgs.Completed += OnReceiveCompleted;
    receiveArgs.UserToken = socket;
    if (!socket.ReceiveAsync(receiveArgs))
    {
        // 操作同步完成
        OnReceiveCompleted(socket, receiveArgs);
    }
}
private void OnReceiveCompleted(object sender, SocketAsyncEventArgs e)
{
    Socket socket = (Socket)e.UserToken;
    
    if (e.SocketError == SocketError.Success && e.BytesTransferred > 0)
    {
        // 处理接收到的数据
        byte[] data = new byte[e.BytesTransferred];
        Buffer.BlockCopy(e.Buffer, e.Offset, data, 0, e.BytesTransferred);
        Console.WriteLine($"Received {e.BytesTransferred} bytes: {Encoding.UTF8.GetString(data)}");
        
        // 继续接收
       
    }
    else
    {
        // 连接已关闭或出错
        Console.WriteLine("Connection closed or error occurred");
        socket.Close();
    }
}DisconnectAsync
public void DisconnectSocket(Socket socket)
{
    var disconnectArgs = new SocketAsyncEventArgs();
    disconnectArgs.Completed += OnDisconnectCompleted;
    disconnectArgs.UserToken = socket;
    disconnectArgs.DisconnectReuseSocket = false; // 是否重用socket
    if (!socket.DisconnectAsync(disconnectArgs))
    {
        // 操作同步完成
        OnDisconnectCompleted(socket, disconnectArgs);
    }
}
private void OnDisconnectCompleted(object sender, SocketAsyncEventArgs e)
{
    if (e.SocketError == SocketError.Success)
    {
        Console.WriteLine("Disconnected successfully");
        Socket socket = (Socket)e.UserToken;
        socket.Close();
    }
    else
    {
        Console.WriteLine($"Disconnect error: {e.SocketError}");
    }
}Socket同步
第一版 Echo程序
此版本主要实现基础通信流程步骤
Echo 程序是最基础的网络通信案例,它能够将客户端发送的消息原样返回。
同步案例均使用同步API实现,是阻塞方法,会卡住程序进程直到成功响应。
客户端
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
using System.Text;
public class EchoClient : MonoBehaviour
{
    public InputField inputTxt;
    public Text txtShow;
    private Socket clientSocket;
    public void OnConnect()
    {
        if (clientSocket != null) return;
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        clientSocket.Connect(endPoint);
        txtShow.text = "成功连接服务器!";
    }
    //发送数据
    public void OnSend()
    {
        if (clientSocket == null) return;
        var str = inputTxt.text;
        var sendBytes = Encoding.UTF8.GetBytes(str);
        clientSocket.Send(sendBytes);
        txtShow.text = "成功发送消息!";
        if (str == "Close")
        {
            OnClose();
        }
        else
        {
            OnReceive();
        }
    }
    //接收数据
    public void OnReceive()
    {
        if (clientSocket == null) return;
        var buffer = new byte[1024];
        var index = clientSocket.Receive(buffer);
        var recStr = Encoding.UTF8.GetString(buffer, 0, index);
        txtShow.text = recStr;
    }
    //关闭Socket
    public void OnClose()
    {
        if (clientSocket == null) return;
        clientSocket.Shutdown(SocketShutdown.Both);
        clientSocket.Close();
    }
}
服务端
using System.Text;
using System.Net;
using System.Net.Sockets;
public class EchoServer
{
    private Socket serverSocket;
    public byte[] bufferArray;
    public void Start()
    {
        if (serverSocket == null)
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        if (bufferArray == null)
        {
            bufferArray = new byte[1024];
        }
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        //绑定服务器IP地址和端口号
        serverSocket.Bind(endPoint);
        //开启监听,等待客户端连接
        //参数backlog指定队列中最多可容纳等待接受的连接数,0表示不限制
        serverSocket.Listen(0);
        Console.WriteLine("服务器启动成功!");
        //成功接收一个客户端连接
        var clientSocket = serverSocket.Accept();
        Console.WriteLine("有一个客户端连入!");
        Array.Clear(bufferArray);
        while (true)
        {
            //接收客户端发来的消息
            var index = clientSocket.Receive(bufferArray);
            var recStr = Encoding.UTF8.GetString(bufferArray, 0, index);
            Console.WriteLine($"客户端发来消息:{recStr}");
            //向客户端发送消息
            var sendBytes = Encoding.UTF8.GetBytes($"我收到了你的消息:{recStr}");
            clientSocket.Send(sendBytes);
            Array.Clear(bufferArray);
            if (recStr == "Close")
            {
                break;
            }
        }
        Console.WriteLine("服务器关闭!");
        serverSocket.Close();
    }
}第二版 多人聊天室
此版本主要实现需求:
1、多个客户端可连接
2、服务器可处理多个客户端的连入和消息广播
3、因为使用同步方法,为避免阻塞主线,使用多线程来处理对应的同步逻辑。
4、服务器使用一个容器来缓存已连接的客户端Socket,用于处理广播和持续通信。
客户端
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
using System.Text;
using System.Threading;
public class SimpleClient : MonoBehaviour
{
    public InputField inputTxt;
    public Text txtShow;
    private Socket clientSocket;
    private bool isClose = true;
    private Queue<string> msgList;
    private StringBuilder sb;
    
    private void Update()
    {
        if (msgList == null) return;
        if (msgList.Count > 0)
        {
            sb.Clear();
            sb.Append(txtShow.text);
            while (msgList.Count > 0)
            {
                sb.Append(msgList.Dequeue());
                sb.Append("\n");
            }
            txtShow.text = sb.ToString();
        }
    }
    public void OnConnect()
    {
        if (clientSocket != null) return;
        if (msgList == null)
        {
            msgList = new Queue<string>();
        }
        sb = new StringBuilder();
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        clientSocket.Connect(endPoint);
        txtShow.text = "成功连接服务器!\n";
        isClose = false;
        ThreadPool.QueueUserWorkItem(OnReceive);
    }
    //发送数据
    public void OnSend()
    {
        if (clientSocket == null) return;
        var str = inputTxt.text;
        var sendBytes = Encoding.UTF8.GetBytes(str);
        clientSocket.Send(sendBytes);
        inputTxt.text = "";
        Debug.Log("成功发送消息!");
    }
    //接收数据
    public void OnReceive(object obj)
    {
        while (!isClose)
        {
            if (clientSocket == null) return;
            var buffer = new byte[1024];
            var index = clientSocket.Receive(buffer);
            var recStr = Encoding.UTF8.GetString(buffer, 0, index);
            msgList.Enqueue(recStr);
        }
    }
    //关闭Socket
    public void OnClose()
    {
        if (clientSocket == null)
        {
            Application.Quit();
            return;
        }
        var sendBytes = Encoding.UTF8.GetBytes("Quit");
        clientSocket.Send(sendBytes);
        Debug.Log("关闭Socket");
        isClose = true;
        clientSocket.Shutdown(SocketShutdown.Both);
        clientSocket.Close();
        Application.Quit();
    }
}
服务端
using System.Text;
using System.Net;
using System.Net.Sockets;
public class BetterServer()
{
    private Socket serverSocket;
    private Dictionary<int, ClientSocket> clientList;
    private bool isColse = true;
    private int clientFlag = 0;
    public void Start(string ip,int port)
    {
        if (serverSocket != null) return;
        if(clientList == null)
        {
            clientList = new Dictionary<int, ClientSocket>();   
        }
        serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint iPEndPoint = new IPEndPoint(IPAddress.Parse(ip), port);
        serverSocket.Bind(iPEndPoint);
        isColse = false;
        serverSocket.Listen(0);
        Console.WriteLine("服务器启动成功!");
        ThreadPool.QueueUserWorkItem(Accect);
    }
    //等待接收客户端连接请求
    public void Accect(object obj)
    {
        while (!isColse)
        {
            var client = serverSocket.Accept();
            clientFlag++;
          
            ClientSocket clientSocket = new ClientSocket(clientFlag, client);
            clientList.TryAdd(clientFlag, clientSocket);
            var connectTip = $"有一个客户端:{clientSocket.id}连入!";
            Console.WriteLine(connectTip);  
            Broadcast(connectTip);
            ThreadPool.QueueUserWorkItem((obj) =>
            {
                while (!isColse)
                {
                    var str = clientSocket.Receive(() =>
                    {
                        clientList.Remove(clientSocket.id);  
                        clientSocket.Close();
                        Console.WriteLine($"还有{clientList.Count}个客户端连接中");  
                    });
                    if (!string.IsNullOrEmpty(str))
                    {
                        Broadcast(str); 
                    };   
                }
            });
        }
    }
    //向客户端广播消息
    public void Broadcast(string info)
    {
        foreach (ClientSocket client in clientList.Values)
        {
            client.Send(info);
        }
    }
    //关闭服务器
    public void Close()
    {
        if (serverSocket == null) return;
        isColse = true; 
        foreach (var client in clientList.Values)
        {
            client.Close();   
        }
        serverSocket.Shutdown(SocketShutdown.Both);
        serverSocket.Close();
    }
}
public class ClientSocket
{
    public int id;
    private Socket clientSocket;    
    public ClientSocket(int clientId,Socket instance)
    {
        id = clientId;
        clientSocket = instance;
    }
    public void Send(string str)
    {
        if (clientSocket == null) return;
        ThreadPool.QueueUserWorkItem((a) =>
        {
            var sendBytes = Encoding.UTF8.GetBytes(str);    
            clientSocket.Send(sendBytes);
        });
    }
    public string Receive(Action callback)
    {
        if (clientSocket != null && clientSocket.Available > 0)
        {
            var buffer = new byte[1024];
            var index = clientSocket.Receive(buffer);
            var recvStr = Encoding.UTF8.GetString(buffer, 0, index);
            var isQuit = recvStr == "Quit";
            if (isQuit)
            {
                callback?.Invoke();
            }
            var msg = isQuit ? $"客户端{id}离开了" : $"客户端{id}:{recvStr}";
            Console.WriteLine(msg);
            return msg;
        }
        return "";
    }
    public void Close()
    {
        if (clientSocket == null) return;
        clientSocket.Shutdown(SocketShutdown.Both); 
        clientSocket.Close();
        clientSocket = null;
    }
}
BetterServer server = new BetterServer();
server.Start("127.0.0.1",8080);
while (true)
{
    var flag = Console.ReadLine();  
    if(flag == "Close")
    {
        server.Close(); 
        break;  
    }
    else if(flag == "广播")
    {
        server.Broadcast("好好学习,天天向上");
    }
}Socket异步
Async方法实现
客户端
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
using System.Text;
public class SimpleClient : MonoBehaviour
{
    public InputField inputTxt;
    public Text txtShow;
    private Socket clientSocket;
    //只有在主线程中才能操作UI组件,由于异步回调是在其他线程执行的。通过缓存接收的数据,再在Update中进行读取并传递给UI组件
    private Queue<string> msgList = new Queue<string>();
    private StringBuilder _stringBuilder = new StringBuilder();
    
    private void Update()
    {
        if (msgList.Count > 0)
        {
            _stringBuilder.Clear();
            _stringBuilder.Append(txtShow.text);
            while (msgList.Count > 0)
            {
                _stringBuilder.Append(msgList.Dequeue());
                _stringBuilder.Append("\n");
            }
            txtShow.text = _stringBuilder.ToString();
        }
    }
    //连接服务器
    public void OnConnect()
    {
        if (clientSocket != null) return;
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        var connectArgs = new SocketAsyncEventArgs();
        connectArgs.RemoteEndPoint = endPoint;
        connectArgs.Completed += ConnectCallback;
        if (!clientSocket.ConnectAsync(connectArgs))
        {
            //操作同步完成
            ConnectCallback(clientSocket, connectArgs);
        }
    }
    //连接服务器异步回调
    private void ConnectCallback(object sender, SocketAsyncEventArgs args)
    {
        var socket = (Socket)sender;
        if (args.SocketError == SocketError.Success)
        {
            msgList.Enqueue("成功连接服务器!");
            OnReceive(socket);
        }
        else
        {
            Debug.LogError($"连接服务器失败:{args.SocketError}");
        }
    }
    
    //发送数据
    public void OnSend()
    {
        if (clientSocket == null) return;
        var str = inputTxt.text;
        if (string.IsNullOrEmpty(str))
        {
            return;
        }
        var sendBytes = Encoding.UTF8.GetBytes(str);
        
        var sendArgs = new SocketAsyncEventArgs();
        sendArgs.SetBuffer(sendBytes,0,sendBytes.Length);
        sendArgs.Completed += SendCallback;
        if (!clientSocket.SendAsync(sendArgs))
        {
            //操作同步完成
            SendCallback(clientSocket, sendArgs);
        }
        inputTxt.text = "";
    }
    //发送数据异步回调
    private void SendCallback(object sender, SocketAsyncEventArgs args)
    {
        if (args.SocketError == SocketError.Success)
        {
            Debug.Log("发送消息成功!");
        }
        else
        {
            Debug.LogError($"发送消息失败:{args.SocketError}");
        }
    }
    
    //接收数据
    public void OnReceive(Socket socket)
    {
        if (socket == null) return;
        var receiveArgs = new SocketAsyncEventArgs();
        var readBuff = new byte[1024];
        receiveArgs.SetBuffer(readBuff,0,readBuff.Length);
        receiveArgs.Completed += ReceiveCallback;
        if (!socket.ReceiveAsync(receiveArgs))
        {
            ReceiveCallback(socket, receiveArgs);
        }
    }
    
    //接收数据异步回调
    private void ReceiveCallback(object sender, SocketAsyncEventArgs args)
    {
        if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
        {
            var dataLength = args.BytesTransferred;
            byte[] data = new byte[dataLength];
            Buffer.BlockCopy(args.Buffer,args.Offset,data,0,dataLength);
            var recvMsg = Encoding.UTF8.GetString(data, 0, dataLength);
            msgList.Enqueue(recvMsg);
            // 继续接收下一条消息
            OnReceive((Socket)sender);
        }
        else
        {
            Debug.LogError($"接收数据失败:{args.SocketError}");
            OnClose();
        }
    }
    //关闭Socket
    public void OnClose()
    {
        if (clientSocket == null) return;
        clientSocket.Shutdown(SocketShutdown.Both);
        clientSocket.Close();
        Application.Quit();
    }
}服务端
using System.Text;
using System.Net;
using System.Net.Sockets;
public class EchoServer
{
    private Socket serverSocket;
    private class ClientInfo
    {
        public Socket clientSocket;
        public byte[] readBuff;
        public ClientInfo(Socket socket)
        {
            clientSocket = socket; 
            readBuff = new byte[1024];
        }
    }
    private Dictionary<Socket, ClientInfo> clientList;
    public void Start()
    {
        if (serverSocket == null)
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        if (clientList == null)
        {
            clientList = new Dictionary<Socket, ClientInfo>();
        }
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        //绑定服务器IP地址和端口号
        serverSocket.Bind(endPoint);
        //开启监听,等待客户端连接
        //参数backlog指定队列中最多可容纳等待接受的连接数,0表示不限制
        serverSocket.Listen(0);
        Console.WriteLine("服务器启动成功!");
        //成功接收一个客户端连接
        StartAccept();
        Console.ReadLine(); 
        Console.WriteLine("服务器关闭!");
        serverSocket.Close();
    }
    private void StartAccept()
    {
        //成功接收一个客户端连接
        var acceptArgs = new SocketAsyncEventArgs();
        acceptArgs.Completed += AcceptCallback;
        if (!serverSocket.AcceptAsync(acceptArgs))
        {
            AcceptCallback(serverSocket, acceptArgs);
        }
    }
    //成功接收一个客户连接回调
    private void AcceptCallback(object sender, SocketAsyncEventArgs args)
    {
        var mainSocket = (Socket)sender;    
        if(args.SocketError == SocketError.Success)
        {
            var socket = args.AcceptSocket;
            var clientInfo = new ClientInfo(socket);
            clientList.TryAdd(socket, clientInfo);
            Console.WriteLine($"有一个客户端连入!在线人数:{clientList.Count}");
            //开始接收客户端数据
            StartReceive(clientInfo);
            //继续等待接收下一个客户端连入
            args.AcceptSocket = null; // 必须重置
            if (!mainSocket.AcceptAsync(args))
            {
                AcceptCallback(mainSocket, args);
            };
        }
        else
        {
            Console.WriteLine($"Accept error: {args.SocketError}");
        }
    }
    //接收从客户端发来的消息
    private void StartReceive(ClientInfo clientInfo)
    {
        var receiveArgs = new SocketAsyncEventArgs();
        var readBuff = new byte[1024];  
        receiveArgs.SetBuffer(readBuff,0,readBuff.Length);
        receiveArgs.Completed += ReceiveCallback;
        var socket = clientInfo.clientSocket;
        if (!socket.ReceiveAsync(receiveArgs))
        {
            ReceiveCallback(socket, receiveArgs);
        }
    }
    //接收数据异步回调
    private void ReceiveCallback(object sender, SocketAsyncEventArgs args)
    {
        var clientSocket = (Socket)sender;
        var clientInfo = clientList[clientSocket];
        if (args.BytesTransferred > 0 && args.SocketError == SocketError.Success)
        {
            var dataLength = args.BytesTransferred;
            byte[] data = new byte[dataLength];
            Buffer.BlockCopy(args.Buffer, args.Offset, data, 0, dataLength);
            var recvMsg = Encoding.UTF8.GetString(data, 0, dataLength);
            Console.WriteLine($"接收客户端消息:{recvMsg}");
            //把接收的消息重新返回给客户端
            var sendBytes = Encoding.UTF8.GetBytes($"我收到了你的消息:{recvMsg}");
            StartSend(clientInfo, sendBytes);
            //继续接收客户端消息
            if (!clientSocket.ReceiveAsync(args))
            {
                ReceiveCallback(clientSocket, args);
            }
        }
        else
        {
            Console.WriteLine($"接收数据失败:{args.SocketError}");
            CloseClient(clientInfo);
        }
    }
    //发送消息给客户端
    private void StartSend(ClientInfo clientInfo, byte[] data)
    {
        if (clientInfo == null) return;
        var sendArgs = new SocketAsyncEventArgs();
        sendArgs.SetBuffer(data,0,data.Length);
        sendArgs.Completed += SendCallback;
        var socket = clientInfo.clientSocket;
        if (!socket
            .SendAsync(sendArgs))
        {
            SendCallback(socket, sendArgs);  
        }   
    }
    //发送消息成功回调
    private void SendCallback(object sender,SocketAsyncEventArgs args)
    {
        if(args.SocketError == SocketError.Success)
        {
            Console.WriteLine($"成功告知客户端");
        }
        else
        {
            Console.WriteLine($"发送数据失败:{args.SocketError}");
        }
    }
    //关闭客户端连接
    private void CloseClient(ClientInfo clientInfo)
    {
        if(clientInfo == null) return;
        clientInfo.clientSocket.Close();
        clientList.Remove(clientInfo.clientSocket);
        Console.WriteLine($"客户端断开连接了  在线人数:{clientList.Count}");
    }
}
Begin/End方法实现
客户端
using System;
using System.Collections.Generic;
using UnityEngine;
using System.Net;
using System.Net.Sockets;
using UnityEngine.UI;
using System.Text;
public class SimpleClient : MonoBehaviour
{
    public InputField inputTxt;
    public Text txtShow;
    private Socket clientSocket;
    //只有在主线程中才能操作UI组件,由于异步回调是在其他线程执行的。通过缓存接收的数据,再在Update中进行读取并传递给UI组件
    private Queue<string> msgList = new Queue<string>();
    private StringBuilder _stringBuilder = new StringBuilder();
    private byte[] readBuff = new byte[1024];
    private void Update()
    {
        if (msgList.Count > 0)
        {
            _stringBuilder.Clear();
            _stringBuilder.Append(txtShow.text);
            while (msgList.Count > 0)
            {
                _stringBuilder.Append(msgList.Dequeue());
                _stringBuilder.Append("\n");
            }
            txtShow.text = _stringBuilder.ToString();
        }
    }
    //连接服务器
    public void OnConnect()
    {
        if (clientSocket != null) return;
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        clientSocket.BeginConnect(endPoint, ConnectCallback, clientSocket);
    }
    //连接服务器异步回调
    private void ConnectCallback(IAsyncResult ar)
    {
        try
        {
            var socket = (Socket)ar.AsyncState;
            socket.EndConnect(ar);
            msgList.Enqueue("成功连接服务器!");
            OnReceive();
        }
        catch (SocketException ex)
        {
            Debug.LogError($"连接服务器失败:{ex}");
        }
    }
    
    //发送数据
    public void OnSend()
    {
        if (clientSocket == null) return;
        var str = inputTxt.text;
        var sendBytes = Encoding.UTF8.GetBytes(str);
        clientSocket.BeginSend(sendBytes, 0, sendBytes.Length,SocketFlags.None, SendCallback, clientSocket);
    }
    //发送数据异步回调
    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            var socket = (Socket)ar.AsyncState;
            int count = socket.EndSend(ar);
        }
        catch (SocketException ex)
        {
            Debug.LogError($"发送消息失败:{ex}");
        }
    }
    
    //接收数据
    public void OnReceive()
    {
        if (clientSocket == null) return;
        clientSocket.BeginReceive(readBuff,0,readBuff.Length,SocketFlags.None,ReceiveCallback,clientSocket);
    }
    
    //接收数据异步回调
    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            var socket = (Socket)ar.AsyncState;
            int count = socket.EndReceive(ar);
            var recStr = Encoding.UTF8.GetString(readBuff, 0, count);
            msgList.Enqueue(recStr);
            clientSocket.BeginReceive(readBuff,0,readBuff.Length,SocketFlags.None,ReceiveCallback,clientSocket);
        }
        catch (SocketException ex)
        {
            Debug.LogError($"接收数据失败:{ex}");
        }
    }
    //关闭Socket
    public void OnClose()
    {
        if (clientSocket == null) return;
        clientSocket.Shutdown(SocketShutdown.Both);
        clientSocket.Close();
    }
}服务端
using System.Text;
using System.Net;
using System.Net.Sockets;
public class EchoServer
{
    private Socket serverSocket;
    private class ClientInfo
    {
        public Socket clientSocket;
        public byte[] readBuff;
        public ClientInfo(Socket socket)
        {
            clientSocket = socket; 
            readBuff = new byte[1024];
        }
    }
    private Dictionary<Socket, ClientInfo> clientList;
    public void Start()
    {
        if (serverSocket == null)
        {
            serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        }
        if (clientList == null)
        {
            clientList = new Dictionary<Socket, ClientInfo>();
        }
        IPEndPoint endPoint = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 8080);
        //绑定服务器IP地址和端口号
        serverSocket.Bind(endPoint);
        //开启监听,等待客户端连接
        //参数backlog指定队列中最多可容纳等待接受的连接数,0表示不限制
        serverSocket.Listen(0);
        Console.WriteLine("服务器启动成功!");
        //成功接收一个客户端连接
        serverSocket.BeginAccept(AcceptCallback, serverSocket);
        Console.ReadLine(); 
        Console.WriteLine("服务器关闭!");
        serverSocket.Close();
    }
    private void AcceptCallback(IAsyncResult ar)
    {
        try
        {
            var socket = (Socket)ar.AsyncState;
            var client = socket.EndAccept(ar);
            var clientInfo = new ClientInfo(client);
            clientList.TryAdd(client, clientInfo);  
            clientInfo.clientSocket.BeginReceive(clientInfo.readBuff, 0, clientInfo.readBuff.Length, SocketFlags.None, ReceiveCallback, clientInfo);
            socket.BeginAccept(AcceptCallback, socket);
            Console.WriteLine($"有一个客户端连入!在线人数:{clientList.Count}");
        }
        catch (SocketException ex)
        {
            Console.WriteLine($"发送消息失败:{ex}");
        }
    }
    //发送数据异步回调
    private void SendCallback(IAsyncResult ar)
    {
        try
        {
            var clientInfo = (ClientInfo)ar.AsyncState;
            int count = clientInfo.clientSocket.EndSend(ar);
            Console.WriteLine($"发送消息成功!");
        }
        catch (SocketException ex)
        {
            Console.WriteLine($"发送消息失败:{ex}");
        }
    }
    //接收数据异步回调
    private void ReceiveCallback(IAsyncResult ar)
    {
        try
        {
            var clientInfo = (ClientInfo)ar.AsyncState;
            int count = clientInfo.clientSocket.EndReceive(ar);
            //如果收到客户端关闭连接信号:“if(count)== 0”,断开连接
            if(count == 0)
            {
                clientInfo.clientSocket.Close();
                clientList.Remove(clientInfo.clientSocket);
                Console.WriteLine($"客户端断开连接了  在线人数:{clientList.Count}");
                return;
            }
            var recStr = Encoding.UTF8.GetString(clientInfo.readBuff, 0, count);
            Console.WriteLine($"客户端发来消息:{recStr}");
            var sendBytes = Encoding.UTF8.GetBytes($"我收到了你的消息:{recStr}");
            clientInfo.clientSocket.BeginSend(sendBytes, 0, sendBytes.Length, SocketFlags.None, SendCallback, clientInfo);
            clientInfo.clientSocket.BeginReceive(clientInfo.readBuff, 0, clientInfo.readBuff.Length, SocketFlags.None, ReceiveCallback, clientInfo);
        }
        catch (SocketException ex)
        {
            Console.WriteLine($"接收数据失败:{ex}");
        }
    }
}
到底了~



























