簡體   English   中英

在偵聽器線程委托中從 TCP 斷開連接時的 Unity C# ThreadAbortException

[英]Unity C# ThreadAbortException when disconnecting from TCP in listener thread delegate

我正在使用 Thread 和 TCPClient 對 TCP 服務器進行讀/寫,其中客戶端 Write 初始化 TCPConnect,Read 在響應得到驗證后立即調用 TCPDisconnect。 必須這樣做以確保多個異步用戶的可用套接字(每個客戶端僅每 5-10 秒調用一次)。 但是,在處理線程時斷開連接會引發一系列錯誤。

調用 DisconnectFromTCPServer() => clientReceiveThread.Abort() 時會出現問題,在偵聽器委托 ListenForData() { using (NetworkStream ... ) { ... while ((length = stream.Read ... ) 拋出這些錯誤;

ThreadAbortException:線程被中止。 System.ComponentModel.Win32Exception..ctor (System.Int32 錯誤) (在 <1720f652f31145af877fbb9e0d1ba65c>:0) System.Net.Sockets.SocketException..ctor (System.Net.Sockets.SocketError socketError) (在 <1720f652f31145af877fbb9e0d1ba65c>:0) System.Net.Sockets.Socket.Receive(System.Byte[] 緩沖區,System.Int32 偏移量,System.Int32 大小,System.Net.Sockets.SocketFlags socketFlags)(在 <1720f652f31145af877fbb9e0d1ba65c>:0)System.Net.Sockets。 NetworkStream.Read (System.Byte[] buffer, System.Int32 offset, System.Int32 size) (at <1720f652f31145af877fbb9e0d1ba65c>:0) Rethrow as IOException: Unable to read data from the transport connection: Thread was being aborted.. System. Net.Sockets.NetworkStream.Read(System.Byte[] 緩沖區,System.Int32 偏移量,System.Int32 大小)(在 <1720f652f31145af877fbb9e0d1ba65c>:0)

無論出於何種原因,DisconnestFromTCPServer() 中的 isAlive 標志都沒有在 ListenForData() 委托中被拾取,從而導致上述錯誤。 在從 serverMessage 引入 NewData 驗證之前,此代碼最初一直在工作,然后在從主線程調用響應時設置 = null; 當 NewData = true 時,公共移動 AIResponse()。

        private void ConnectToTcpServer()
        {
            try
            {
                Debug.Log("CONNECTING TO SERVER...");
                clientReceiveThread = new Thread(new ThreadStart(ListenForData));
                clientReceiveThread.IsBackground = true;
                clientReceiveThread.Start();
                isAlive = true;
            }
            catch (Exception e)
            {
                Debug.Log("On client connect exception " + e);
            }
        }

        private void DisconnectFromTcpServer()
        {
            isAlive = false;

            if (socketConnection.Connected) ((IDisposable)socketConnection).Dispose();

            StartCoroutine(ServerDisconnectedCoroutine(() => !socketConnection.Connected));

            if (clientReceiveThread.IsAlive) clientReceiveThread.Abort();
            clientReceiveThread.Join();

            ServerConnected = false;
        }

        private IEnumerator ServerDisconnectedCoroutine(System.Func<bool> socketDisconnected)
        {
            yield return new WaitUntil(socketDisconnected);
        }

        public void ListenForData()
        {
            // SWITCH PORTS ON EACH CONNECT - BALANCE THE LOAD
            // WRAP IN COUNTER
            port = port == 12345 ? 12344 : 12345;

            try
            {
                socketConnection = new TcpClient("65.21.xxx.xxx", 12345);
                Byte[] bytes = new Byte[1024];

                Thread.Sleep(100);

                while (isAlive)
                {
                    // Test socket connection
                    if (!socketConnection.Connected)
                    {
                        Debug.Log("DISCONNECTED LISTEN");
                        serverTimeout();
                        return;
                    }
                    else
                        ServerConnected = true;

                    // Get a stream object for reading              
                    using (NetworkStream stream = socketConnection.GetStream())
                    {
                        int length;
                        // Read incomming stream into byte arrary.                  
                        while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            var incommingData = new byte[length];
                            Array.Copy(bytes, 0, incommingData, 0, length);
                            // Convert byte array to string message.                        
                            serverMessage = Encoding.UTF8.GetString(incommingData);
                            Debug.Log("server message received as: " + serverMessage);
                            // ORIGINAL NewData = true;
                        }

                        stream.Close();
                    }
                }
            }
            catch (SocketException socketException)
            {
                Debug.Log("Socket exception: " + socketException);
            }
            catch (ThreadAbortException threadException)
            {
                Debug.Log("ThradException: " + threadException);
            }
        }

        public bool IfNewData()
        {
            if (serverMessage != null && !NewData) aiDataFromServer.LoadString(serverMessage);
            if (aiDataFromServer.type != "Error") NewData = true;

            return NewData;
        }

        public Move AIResponse()
        {
            NewData = false;
            // ORIGINAL - serverMessage ! set to null
            serverMessage = null;

            DisconnectFromTcpServer();

            return aiDataFromServer.moveData;
        }

我嘗試了各種方法來延遲對 Thread.Abort() 的調用,以及關閉流和套接字,但似乎沒有什么能阻止委托嘗試讀取數據,盡管服務器響應已經記錄在控制台中並且沒有進一步的信息發送。 我不知道下一步該做什么,除非我錯過了一些非常明顯的東西。

感謝任何可以為我指明正確方向的人。

更新 - 初始問題已解決 - 見下文 - 新問題已確定

遵循第一個答案並通過一些挖掘 Thread 錯誤已得到解決(請參見下面的代碼段),但這些更改導致 SocketConnection 的行為出現了奇怪的偽影。

一旦stream.CanRead,stream.DataAvailable,stream.Close(); 循環返回頂部並返回 !serverConnection.Connected => Debug.Log("DISCONNECTED LISTEN"); 導致服務器重新連接。 此時主線程已調用 AIResponse() 並且連接和線程無論如何都已關閉,但我無法確定為什么在讀取流后 socketConnection 被關閉。

public void ListenForData()
{
    // SWITCH PORTS ON EACH CONNECT - BALANCE THE LOAD
    // WRAP IN COUNTER
    port = port == 12345 ? 12344 : 12345;

    try
    {
        socketConnection = new TcpClient("65.21.xxx.xxx", 12345);
        Byte[] bytes = new Byte[1024];

        while (isAlive)
        {
            Debug.Log("IS ALIVE");

            // Test socket connection
            if (!socketConnection.Connected && connectionRequired)
            {
                Debug.Log("DISCONNECTED LISTEN");
                serverTimeout();
                return;
            }
            else
                ServerConnected = true;

            using (NetworkStream stream = socketConnection.GetStream())
            {
                if (stream.CanRead)
                {
                    int _length;

                    do
                    {
                        _length = stream.Read(bytes, 0, bytes.Length);
                        var _incommingData = new byte[_length];
                        Array.Copy(bytes, 0, _incommingData, 0, _length);
                        serverMessage = Encoding.UTF8.GetString(_incommingData);
                        Debug.Log("server message received as: " + serverMessage);

                        // ALLOW REFERENCES TO BE UPDATED
                        if (!stream.DataAvailable)
                            Thread.Sleep(1);
                    }
                    while (stream.DataAvailable);
                }

                stream.Close();

                Debug.Log("STREAM CLOSED");
            }
        }
    }
    catch (SocketException socketException)
    {
        Debug.Log("Socket exception: " + socketException);
    }
    catch (ThreadAbortException threadException)
    {
        Debug.Log("ThradException: " + threadException);
    }
}

雖然這不是一個主要問題,但在這些操作之后連接會關閉似乎很奇怪,除非我錯過了文檔中的某些內容。

再次感謝您的任何見解。

看起來您在閱讀過程中中止了。 請記住,NetworkStream.Read 僅在對方關閉時返回 0,否則將始終返回可用數據或無限期阻塞等待。

這是Stream.Read的每個合同:

在沒有數據可用的情況下,該實現將阻塞直到可以讀取至少一個字節的數據。 僅當流中沒有更多數據並且不需要更多數據時(例如關閉的套接字或文件結尾),Read 才返回 0。

我建議不要在閱讀時使用其他東西,例如 bool 'is alive' 標志。 並且在調用Read之前,調用NetworkStream.DataAvailable,否則會阻塞。

    while(is_alive){
        if(stream.DataAvailable){ stream.Read(...))
        Thread.Sleep(100);
    }

(您也可以將其移動到協程而不是線程中,並保持分配的流直到您退出,而不是一直創建/處理您需要閱讀的時間)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM