网络开发基础(游戏)之 Socket API

news2025/4/20 18:11:06

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) 和 AddressFamily.InterNetwork address 系列。

Dgram:支持数据报,即最大长度固定(通常很小)的无连接、不可靠消息。 消息可能会丢失或重复并可能在到达时不按顺序排列。 Socket 类型的 Dgram 在发送和接收数据之前不需要任何连接,并且可以与多个对方主机进行通信。 Dgram 使用 Datagram 协议 (Udp) 和 AddressFamily.InterNetwork address 系列。

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}");
        }
    }
}

到底了~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2338894.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

行为审计软件:企业合规与内部监控的数字守门人

在当今高度数字化的商业环境中&#xff0c;企业运营产生的电子数据呈指数级增长&#xff0c;员工行为也日益复杂多样。行为审计软件应运而生&#xff0c;成为现代企业管理不可或缺的工具。这类软件通过系统化记录、分析和报告组织内部用户活动&#xff0c;帮助企业管理风险、确…

bat脚本转换为EXE应用程序文件

很多时候,我们使用电脑时会编辑bat脚本文件 很多时候&#xff0c;我们制作的玩笑&#xff0c;病毒也会使用这个格式. 但这个格式也有很多缺点 1,如果是需要管理员运行的程序,需要费劲的自己使用管理员身份运行 2,文件并不为大家所熟知,认同度不高 3,可以非常轻松的看到原代…

细说STM32单片机FreeRTOS任务管理API函数vTaskList()的使用方法

目录 一、函数vTaskList() 1、 函数说明 2、返回的字符串表格说明 3、函数的使用方法 二、 vTaskList()的应用示例 1、示例功能、项目设置 2、软件设计 &#xff08;1&#xff09;main.c &#xff08;2&#xff09;freertos.c &#xff08;3&#xff09;FreeRTOSConf…

DNS主从同步

安装软件 主配置中完成DNS解析&#xff1a;192.168.131.134 [rootlocalhost ~]# mount /dev/sr0 /mnt [rootlocalhost ~]# vim /etc/yum.repos.d/myrepo.repo [base] namebase baseurl/mnt/BaseOS gpgchcek0 enable1 [base2] namebase2 baseurl/mnt/AppStream gpgchcek0 enab…

双指针算法(部分例题解析)

快慢指针左右指针 前言 双指针&#xff0c;它通过设置两个指针来遍历数据&#xff0c;从而实现高效的查找、排序、去重等操作。双指针算法的核心在于通过合理地移动这两个指针&#xff0c;减少不必要的遍历&#xff0c;提高算法的效率。 283. 移动零 - 力扣&#xff08;LeetCo…

解决Windows打印问题的集成软件

家里或公司电脑经常为连不上打印机而烦恼&#xff0c;今天给大家推荐一款修复打印工具&#xff0c;该工具是采用易语言开发的集成化打印机故障修复软件&#xff0c;专为解决 Windows 系统&#xff08;含 32/64 位 Windows 7/10/11&#xff09;中因权限配置、服务异常、补丁缺失…

警惕阿里云中的yum update操作不当导致:/sbin/init被清空导致Linux无法正常启动

由于使用阿里云进行部署测试&#xff0c;因而会对yum update进行操作&#xff0c;这两天更新了systemd-239-82.0.3.4.al8.2.x86_64&#xff0c;但存在报错&#xff0c;然后进行yum history undo和清空yum cache&#xff0c;但出现操作Linux命令行无效。具体来说&#xff0c;几个…

关系型数据库MYSQL(续)

目录 三.MySQL事务原理分析 1.事务是什么&#xff1f; 2.执行事务的目的是什么&#xff1f; 3.事务是由什么组成的&#xff1f; 4.事务的特征是什么&#xff1f; 5.事务控制语句 6.ACID特性 6.1原子性&#xff08;A&#xff09; 6.2隔离性&#xff08;I&#xff09; …

WInform当今技术特性分析

Windows Forms (WinForms) 技术特性分析 引言 Windows Forms (WinForms) 作为微软最早推出的基于.NET的图形用户界面开发框架&#xff0c;已经存在了20多年。在如今充满了各种现代UI框架的软件开发生态系统中&#xff0c;WinForms仍然保持着其独特的地位。本文将深入分析WinF…

运筹学之模拟退火

目录 一、历史二、精髓思想三、案例与代码实现 一、历史 问&#xff1a;谁在什么时候提出模拟退火&#xff1f;答&#xff1a;模拟退火算法&#xff08;Simulated Annealing&#xff0c;SA&#xff09;是由斯图尔特柯尔斯基&#xff08;Scott Kirkpatrick&#xff09; 等人在 …

树莓派5-开发应用笔记

0.树莓派系统目录 /home&#xff1a;用户目录。 除了root用户外&#xff0c;其他所有的使用者的数据都存放在这个目录下&#xff0c;在树莓派的系统中&#xff0c;/home目录中有一个pi的子目录,这个就是pi用户的默认目录。 /bin&#xff1a; 主要放置系统的必备执行文件目录。 …

8.5/Q1,Charls最新文章解读

文章题目&#xff1a;Atherogenic index of plasma, high sensitivity C-reactive protein and incident diabetes among middle-aged and elderly adults in China: a national cohort study DOI&#xff1a;10.1186/s12933-025-02653-4 中文标题&#xff1a;中国中老年人群血…

k8s 调整Node节点 Max_Pods

默认情况下&#xff0c;Kubernetes集群中一个Node最多能起110个Pod。 这是基于性能和资源管理的考虑&#xff0c;以确保Kubernetes集群的稳定性和可靠性。 查看kht125节点上支持的最大pod数量: kubectl describe node kht125 | grep -i “Capacity|Allocatable” -A 6 调整…

使用Service发布前后端应用程序

使用Service发布前后端应用程序 文章目录 使用Service发布前后端应用程序[toc]一、创建并发布后端应用程序二、创建并发布前端应用程序三、通过前端发送流量进行测试 部署前端&#xff08;Frontend&#xff09;微服务和后端&#xff08;Backend&#xff09;微服务是比较常见的应…

Ubuntu20.04下Docker方案实现多平台SDK编译

0 前言 熟悉嵌入式平台Linux SDK编译流程的小伙伴都知道,假如平台a要求必须在Ubuntu18.04下编译,平台b要求要Ubuntu22.04的环境,那我只有Ubuntu20.04,或者说我的电脑硬件配置最高只能支持Ubuntu20.04怎么办?强行在Ubuntu20.04下编译,编又编不过,换到旧版本我又不愿意,…

-SSRF 服务端请求Gopher 伪协议无回显利用黑白盒挖掘业务功能点

1 、 SSRF 漏洞原理 SSRF(Server-Side Request Forgery: 服务器端请求伪造 ) 一种由攻击者构造形成由服务端发起请求的一个安全漏洞 ; 一般情况下&#xff0c; SSRF 攻击的目标是从外网无法访问的内部系统。 &#xff08;正是因为它是由服务端发起的&#xff0c;所以它能…

《AI大模型应知应会100篇》第27篇:模型温度参数调节:控制创造性与确定性

第27篇&#xff1a;模型温度参数调节&#xff1a;控制创造性与确定性 摘要 在大语言模型的使用中&#xff0c;“温度”&#xff08;Temperature&#xff09;是一个关键参数&#xff0c;它决定了模型输出的创造性和确定性之间的平衡。通过调整温度参数&#xff0c;您可以根据任…

聊聊Doris的数据模型,如何用结构化设计解决实时分析难题

传统 OLAP 系统的局限 在大数据实时分析领域&#xff0c;数据模型设计直接决定了系统的查询性能、存储效率与业务适配性。Apache Doris作为新一代MPP分析型数据库&#xff0c;通过独创的多模型融合架构&#xff0c;在业内率先实现了"一份数据支持多种分析范式"的能力…

LNA设计

设计目的 为后级提供足够的增益以克服后级电路噪声 尽可能小的噪声和信号失真 确保输入和输出端的阻抗匹配 确保信号线性度 评价标准 噪声系数 功率增益 工作频率和带宽 输入信号功率动态范围 端口电压驻波比 稳定性 基于SP模型的LNA设计 直流分析 S参数分析 设计指标 &#xf…

JavaSpring 中使用 Redis

创建项目 配置 Redis 服务地址 创建 Controller 类 由于当前只是些简单的测试代码&#xff0c;所以就不进行分层了&#xff0c;只创建一个 Controller 来实现 jedis 通过 jedis 对象里的各种方法来操作 Redis 此处通过 StringRedisTemplate 来操作 Redis 最原始提供的类是 Re…