首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在侦听器线程委托中与TCP断开连接时,统一C# ThreadAbortException

在侦听器线程委托中与TCP断开连接时,统一C# ThreadAbortException
EN

Stack Overflow用户
提问于 2022-07-11 14:54:43
回答 1查看 144关注 0票数 1

我使用线程和TCPClient对TCP服务器进行读/写,其中客户端写初始化TCPConnect,并在响应验证后立即调用TCPDisconnect。必须这样做,以确保多个异步用户可用的套接字(每个客户端仅每5-10秒调用一次)。但是,当处理线程时,断开将引发一系列错误。

当调用DisconnectFromTCPServer() => clientReceiveThread.Abort()时,在侦听器委托ListenForData() { The (NetworkStream .){.时间(长度= stream.Read .)抛出这些错误;

ThreadAbortException:线程被中止。System.ComponentModel.Win32Exception..ctor (System.Int32 error) (at <1720f652f31145af877fbb9e0d1ba65c>:0) System.Net.Sockets.SocketException..ctor (System.Net.Sockets.SocketError socketError) (at <1720f652f31145af877fbb9e0d1ba65c>:0) System.Net.Sockets.Socket.Receive (System.Byte[]缓冲区,System.Int32偏移量,System.Int32大小,System.Net.Sockets.SocketFlags socketFlags) (at <1720f652f31145af877fbb9e0d1ba65c>:0) System.Net.Sockets.NetworkStream.Read (System.Byte[]缓冲器,System.Int32偏移量,System.Int32大小)(在<1720f652f31145af877fbb9e0d1ba65c>:0)重新抛出为IOException:无法从传输连接读取数据:线程被中止。System.Net.Sockets.NetworkStream.Read (System.Byte[]缓冲器,System.Int32偏移量,System.Int32大小) (at <1720f652f31145af877fbb9e0d1ba65c>:0)

出于任何原因,isAlive ()中的DisconnestFromTCPServer()标志没有在ListenForData()委托中被选中,从而导致上述错误。在从主线程调用响应时,当从NewData = true调用响应时,这段代码最初是在从serverMessage中引入对NewData的验证之前,然后设置= null。

代码语言:javascript
运行
复制
        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 incoming stream into byte arrary.                   
                        while ((length = stream.Read(bytes, 0, bytes.Length)) != 0)
                        {
                            var incomingData = new byte[length];
                            Array.Copy(bytes, 0, incomingData, 0, length);
                            // Convert byte array to string message.                        
                            serverMessage = Encoding.UTF8.GetString(incomingData);
                            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()的调用,以及关闭流和套接字,但是似乎没有什么能阻止委托尝试读取数据,尽管服务器响应已经记录在控制台中,并且没有发送进一步的信息。我对下一步该做什么有点不知所措,除非我错过了一些显而易见的事情。

感谢任何能为我指明正确方向的人。

更新-初始问题已解决-见下文-新问题已确定

按照第一个答案,并对线程错误进行了一些挖掘,已经解决了线程错误(请参阅下面的片段),但是这些更改在SocketConnection的行为中造成了一个奇怪的伪影。

一旦stream.CanRead,stream.DataAvailable,stream.Close();循环返回到top并返回!serverConnection.Connected => Debug.Log(“断开连接侦听”);导致服务器重新连接。此时主线程调用了AIResponse(),连接和线程无论如何都被关闭了,但是我无法确定为什么在读取流之后关闭socketConnection。

代码语言:javascript
运行
复制
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 _incomingData = new byte[_length];
                        Array.Copy(bytes, 0, _incomingData, 0, _length);
                        serverMessage = Encoding.UTF8.GetString(_incomingData);
                        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);
    }
}

虽然这不是一个主要的问题,但在这些操作之后,连接被关闭似乎是非常奇怪的,除非我错过了文档中的一些内容。

再次感谢您的洞察力。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-07-11 17:24:18

看上去你在阅读过程中失败了。请记住,只有当另一方关闭时,NetworkStream.Read才会返回0,否则始终会返回可获取的数据或无限期地等待。

这是Stream.Read的合同

如果没有可用的数据,实现将阻塞,直到至少可以读取一个字节的数据。只有当流中没有更多的数据并且不需要更多的数据(例如关闭的套接字或文件结束时),Read才返回0。

我建议你不要大声呼喊你的读物,而不是其他的东西,比如“是活的”旗子。在调用Read之前,调用NetworkStream.DataAvailable,否则将阻塞。

代码语言:javascript
运行
复制
    while(is_alive){
        if(stream.DataAvailable){ stream.Read(...))
        Thread.Sleep(100);
    }

(您也可以将它移动到协同线而不是线程,并将流分配到退出,而不是创建/处理所有需要读取的时间)

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72940509

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档