无法访问已处置的对象。对象名称:'System.Net.Sockets.UdpClient'

Posted

技术标签:

【中文标题】无法访问已处置的对象。对象名称:\'System.Net.Sockets.UdpClient\'【英文标题】:Cannot access a disposed object. Object name: 'System.Net.Sockets.UdpClient'无法访问已处置的对象。对象名称:'System.Net.Sockets.UdpClient' 【发布时间】:2022-01-11 01:44:28 【问题描述】:

我正在玩多人游戏,我的 Unity 控制台显示此错误“无法访问已处置的对象。 对象名称:'System.Net.Sockets.UdpClient'。”当我关闭服务器时。我不知道如何处理它......谁能告诉我如何解决这个问题?

这是我的 Server.cs 文件:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using UnityEngine;

public class Server

    public static int MaxPlayers  get; private set; 
    public static int Port  get; private set; 
    public static Dictionary<int, Client> clients = new Dictionary<int, Client>();
    public delegate void PacketHandler(int _fromClient, Packet _packet);
    public static Dictionary<int, PacketHandler> packetHandlers;

    private static TcpListener tcpListener;
    private static UdpClient udpListener;

    /// <summary>Starts the server.</summary>
    /// <param name="_maxPlayers">The maximum players that can be connected simultaneously.</param>
    /// <param name="_port">The port to start the server on.</param>
    public static void Start(int _maxPlayers, int _port)
    
        MaxPlayers = _maxPlayers;
        Port = _port;

        Debug.Log("Starting server...");
        InitializeServerData();

        tcpListener = new TcpListener(IPAddress.Any, Port);
        tcpListener.Start();
        tcpListener.BeginAcceptTcpClient(TCPConnectCallback, null);

        udpListener = new UdpClient(Port);
        udpListener.BeginReceive(UDPReceiveCallback, null);

        Debug.Log($"Server started on port Port.");
    

    /// <summary>Handles new TCP connections.</summary>
    private static void TCPConnectCallback(IAsyncResult _result)
    
        TcpClient _client = tcpListener.EndAcceptTcpClient(_result);
        tcpListener.BeginAcceptTcpClient(TCPConnectCallback, null);
        Debug.Log($"Incoming connection from _client.Client.RemoteEndPoint...");

        for (int i = 1; i <= MaxPlayers; i++)
        
            if (clients[i].tcp.socket == null)
            
                clients[i].tcp.Connect(_client);
                return;
            
        

        Debug.Log($"_client.Client.RemoteEndPoint failed to connect: Server full!");
    

    /// <summary>Receives incoming UDP data.</summary>
    private static void UDPReceiveCallback(IAsyncResult _result)
    
        try
        
            IPEndPoint _clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
            byte[] _data = udpListener.EndReceive(_result, ref _clientEndPoint);
            udpListener.BeginReceive(UDPReceiveCallback, null);

            if (_data.Length < 4)
            
                return;
            

            using (Packet _packet = new Packet(_data))
            
                int _clientId = _packet.ReadInt();

                if (_clientId == 0)
                
                    return;
                

                if (clients[_clientId].udp.endPoint == null)
                
                    // If this is a new connection
                    clients[_clientId].udp.Connect(_clientEndPoint);
                    return;
                

                if (clients[_clientId].udp.endPoint.ToString() == _clientEndPoint.ToString())
                
                    // Ensures that the client is not being impersonated by another by sending a false clientID
                    clients[_clientId].udp.HandleData(_packet);
                
            
        
        catch (Exception _ex)
        
            Debug.Log($"Error receiving UDP data: _ex");
        
    

    /// <summary>Sends a packet to the specified endpoint via UDP.</summary>
    /// <param name="_clientEndPoint">The endpoint to send the packet to.</param>
    /// <param name="_packet">The packet to send.</param>
    public static void SendUDPData(IPEndPoint _clientEndPoint, Packet _packet)
    
        try
        
            if (_clientEndPoint != null)
            
                udpListener.BeginSend(_packet.ToArray(), _packet.Length(), _clientEndPoint, null, null);
            
        
        catch (Exception _ex)
        
            Debug.Log($"Error sending data to _clientEndPoint via UDP: _ex");
        
    

    /// <summary>Initializes all necessary server data.</summary>
    private static void InitializeServerData()
    
        for (int i = 1; i <= MaxPlayers; i++)
        
            clients.Add(i, new Client(i));
        

        packetHandlers = new Dictionary<int, PacketHandler>()
        
             (int)ClientPackets.welcomeReceived, ServerHandle.WelcomeReceived ,
             (int)ClientPackets.playerMovement, ServerHandle.PlayerMovement ,
             (int)ClientPackets.playerShoot, ServerHandle.PlayerShoot ,
             (int)ClientPackets.playerThrowItem, ServerHandle.PlayerThrowItem 
        ;
        Debug.Log("Initialized packets.");
    

    public static void Stop()
    
        tcpListener.Stop();
        udpListener.Close();
    

我制作多人游戏的教程:

https://www.youtube.com/playlist?list=PLXkn83W0QkfnqsK8I0RAz5AbUxfg3bOQ5

【问题讨论】:

【参考方案1】:

这是因为垃圾收集器已释放 udpClient,而您正试图在已释放对象中调用 Stop() 方法。 因此,请尝试替换此方法而不是您的 Stop 方法

public static void Stop()

    try
    
       tcpListener.Stop();
       udpListener.Close();
    
    catch 

【讨论】:

问题仍然存在...

以上是关于无法访问已处置的对象。对象名称:'System.Net.Sockets.UdpClient'的主要内容,如果未能解决你的问题,请参考以下文章

无法访问已处置的对象 - 如何修复?

引发线程事件时无法访问已处置的对象

无法在单元测试中访问已处置的对象

使用异步存储库模式 - 无法访问已处置的对象

通过 Azure 函数注入 DbContext 时无法访问已处置的对象

无法访问已处置的对象 VC++ VS2017 Professional