Об ошибке Unity: «SocketException: только одно использование каждого адреса сокета» - PullRequest
0 голосов
/ 21 января 2020

Я хочу раздать следующий код пользователям для получения UDP:

UDPReceive.cs

using UnityEngine;
using System.Collections;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

public class UDPReceive : MonoBehaviour
{
    int LOCA_LPORT = 22222;
    static UdpClient udp;
    Thread thread;

    void Start ()
    {
        udp = new UdpClient(LOCA_LPORT);
        udp.Client.ReceiveTimeout = 1000;
        thread = new Thread(new ThreadStart(ThreadMethod));
        thread.Start(); 
    }

    void Update ()
    {
    }

    void OnApplicationQuit()
    {
        thread.Abort();
    }

    private static void ThreadMethod()
    {
        while(true)
        {
            IPEndPoint remoteEP = null;
            byte[] data = udp.Receive(ref remoteEP);
            string text = Encoding.ASCII.GetString(data);
            Debug.Log(text);
        }
    } 
}

https://qiita.com/nenjiru/items/8fa8dfb27f55c0205651

Однако, если пользователь присоединяет этот файл к нескольким объектам, выдается сообщение об ошибке.

Сообщение об ошибке выглядит следующим образом.

"SocketException: Only one usage of each socket address"

System.Net.Sockets.Socket.Bind (System.Net.EndPoint local_end)
System.Net.Sockets.UdpClient.InitSocket (System.Net.EndPoint localEP)
System.Net.Sockets.UdpClient..ctor (Int32 port)
UDPReceive.Start () (at Assets/UDPReceive.cs:16)

Если только "I" используйте этот файл, это не проблема, если я не буду прикреплять его к нескольким объектам.

Однако при использовании «другими пользователями» пользователи могут задаться вопросом, почему возникает ошибка.

Итак, когда пользователь сталкивается с этой ошибкой, я хочу дать сообщение «Этот сценарий не должен прикрепляться более чем к одному объекту».

Как я могу сделать такую ​​вещь?

1 Ответ

1 голос
/ 21 января 2020

, почему ошибка возникает, само собой разумеется, и я думаю, что у вас уже есть проблема: вы можете прослушивать один порт только один раз. Второй сценарий должен был бы использовать другой порт.


Как избежать этого и дать правильное предупреждение / ошибку?

Есть много вариантов.

  • Можно, например, проверить, сколько в сцене, используя FindObjectsOfType, как, например,

    private void Awake()
    {
        var instances = FindObjectsOfType<UDPReceive>();
    
        if(instances.Length > 1)
        {
            Debug.LogError("Found multiple instances of UDPReceive! Only one is allowed!");
        }
    }
    

    , что вы могли бы также сделать в Reset который вызывается, как только компонент присоединяется к объекту. Таким образом, вы уже могли показать ошибку еще до запуска PlayMode!

  • Другим примером будет классический Singleton-Pattern

    // as this is static it is "shared" between all instances or
    // better said it is not bound to any instance at all
    private static UDPReceive instance;
    
    private void Awake()
    {
        // check if another instance already exists
        if(instance && instance != this)
        {
            Debug.LogError("There is already another instance of UDPReceive in the scene! Only one is allowed!", this);
            Debug.LogError("That's true, I am the active instance for this scene", instance);
    
            this.enabled = false;
            return;
        }
    
        // otherwise become the instance yourself
        instance = this;
    }
    
  • Вы также можете перехватить исключение и показать свое собственное сообщение, например,

    void Start ()
    {
        try
        {
            udp = new UdpClient(LOCA_LPORT);
            udp.Client.ReceiveTimeout = 1000;
            thread = new Thread(new ThreadStart(ThreadMethod));
            thread.Start();
        }
        // If any SocketException is thrown while starting the UDP client
        // it is most probably due to the port already being in use
        catch(SocketException e)
        {
            Debug.LogError("UDP cliente has a SocketException." 
               + "/nThis is probably caused by the target port already being used by something else." 
               + "/nMake sure you have only one instance of UDPReceive in your scene and try again", this);
        } 
    }
    

В качестве примечания: на самом деле можно использовать это несколько раз в одной и той же сцене, просто позволяя разработчику выбрать другой порт:

//                                | probably a typo btw ;)
//                                v 
[SerializeField] private int LOCA_LPORT = 22222;

По-прежнему используется 22222 по умолчанию, но теперь кто-то может также использовать пользовательский. (Затем вы должны, конечно, переименовать его в соответствии с c# соглашениями по кодированию)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...