编写时的线程串口IOException

时间:2023-02-10 15:10:27

I'm trying to write a small application that simply reads data from a socket, extracts some information (two integers) from the data and sends the extracted information off on a serial port.

我正在尝试编写一个简单的应用程序,它只是从套接字读取数据,从数据中提取一些信息(两个整数),并在串行端口上发送提取的信息。

The idea is that it should start and just keep going. In short, it works, but not for long. After a consistently short period I start to receive IOExceptions and socket receive buffer is swamped.

这个想法是它应该开始并继续前进。简而言之,它有效,但不会长久。经过一段短暂的时间后,我开始接收IOExceptions并且套接字接收缓冲区被淹没。

The thread framework has been taken from the MSDN serial port example.

线程框架取自MSDN串口示例。

The delay in send(), readThread.Join(), is an effort to delay read() in order to allow serial port interrupt processing a chance to occur, but I think I've misinterpreted the join function. I either need to sync the processes more effectively or throw some data away as it comes in off the socket, which would be fine. The integer data is controlling a pan tilt unit and I'm sure four times a second would be acceptable, but not sure on how to best acheive either, any ideas would be greatly appreciated, cheers.

send(),readThread.Join()的延迟是为了使串口中断处理有机会发生延迟read(),但我认为我误解了join函数。我要么需要更有效地同步进程,要么抛出一些数据,因为它来自套接字,这没关系。整数数据控制着一个平移单元,我确信每秒四次是可以接受的,但不确定如何最好的实现,任何想法都会非常感激,欢呼。

using System;
using System.Collections.Generic;
using System.Text;
using System.IO.Ports;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;


namespace ConsoleApplication1
{
    class Program
    {
        static bool _continue;
        static SerialPort _serialPort;
        static Thread readThread;
        static Thread sendThread;
        static String sendString;
        static Socket s;
        static int byteCount;
        static Byte[] bytesReceived;

        // synchronise send and receive threads
        static bool dataReceived;

        const int FIONREAD = 0x4004667F;

        static void Main(string[] args)
        {
            dataReceived = false;
            readThread = new Thread(Read);
            sendThread = new Thread(Send);

            bytesReceived = new Byte[16384];

            // Create a new SerialPort object with default settings.
            _serialPort = new SerialPort("COM4", 38400, Parity.None, 8, StopBits.One);

            // Set the read/write timeouts
            _serialPort.WriteTimeout = 500;

            _serialPort.Open();
            string moveMode = "CV ";
            _serialPort.WriteLine(moveMode);

            s = null;
            IPHostEntry hostEntry = Dns.GetHostEntry("localhost");
            foreach (IPAddress address in hostEntry.AddressList)
            {
                IPEndPoint ipe = new IPEndPoint(address, 10001);
                Socket tempSocket =
                    new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                tempSocket.Connect(ipe);

                if (tempSocket.Connected)
                {
                    s = tempSocket;
                    s.ReceiveBufferSize = 16384;
                    break;
                }
                else
                {
                    continue;
                }
            }

            readThread.Start();
            sendThread.Start();

            while (_continue)
            {
                Thread.Sleep(10);
                ;// Console.WriteLine("main...");
            }

            readThread.Join();
            _serialPort.Close();
            s.Close();
        }

        public static void Read()
        {
            while (_continue)
            {
                try
                {
                    //Console.WriteLine("Read");
                    if (!dataReceived)
                    {
                        byte[] outValue = BitConverter.GetBytes(0);
                        // Check how many bytes have been received.
                        s.IOControl(FIONREAD, null, outValue);
                        uint bytesAvailable = BitConverter.ToUInt32(outValue, 0);

                        if (bytesAvailable > 0)
                        {
                            Console.WriteLine("Read thread..." + bytesAvailable);
                            byteCount = s.Receive(bytesReceived);
                            string str = Encoding.ASCII.GetString(bytesReceived);
                            //str = Encoding::UTF8->GetString( bytesReceived );
                            string[] split = str.Split(new Char[] { '\t', '\r', '\n' });

                            string filteredX = (split.GetValue(7)).ToString();
                            string filteredY = (split.GetValue(8)).ToString();

                            string[] AzSplit = filteredX.Split(new Char[] { '.' });
                            filteredX = (AzSplit.GetValue(0)).ToString();
                            string[] ElSplit = filteredY.Split(new Char[] { '.' });
                            filteredY = (ElSplit.GetValue(0)).ToString();

                            // scale values 
                            int x = (int)(Convert.ToInt32(filteredX) * 1.9);
                            string scaledAz = x.ToString();
                            int y = (int)(Convert.ToInt32(filteredY) * 1.9);
                            string scaledEl = y.ToString();

                            String moveAz = "PS" + scaledAz + " ";
                            String moveEl = "TS" + scaledEl + " ";

                            sendString = moveAz + moveEl;
                            dataReceived = true;
                        }
                    }
                }
                catch (TimeoutException) {Console.WriteLine("timeout exception");}
                catch (NullReferenceException) {Console.WriteLine("Read NULL reference  exception");}
            }
        }

        public static void Send()
        {
            while (_continue)
            {
                try
                {
                    if (dataReceived)
                    {
                        // sleep Read() thread to allow serial port interrupt     processing 
                        readThread.Join(100);
                        // send command to PTU
            dataReceived = false;
                        Console.WriteLine(sendString);
                        _serialPort.WriteLine(sendString);
                    }
                }
                catch (TimeoutException) { Console.WriteLine("Timeout exception"); }
                catch (IOException) { Console.WriteLine("IOException exception"); }
                catch (NullReferenceException) { Console.WriteLine("Send NULL reference exception"); }
            }
        }
    }
}

UPDATE:

Thanks for the response Jon.

感谢Jon的回应。

What I'm attempting to do is poll a socket for data, if its there process it and send it to the serial port, else keep polling the socket , repeating this whole process ad nauseum.

我正在尝试做的是轮询套接字以获取数据,如果它在那里处理它并将其发送到串行端口,否则继续轮询套接字,重复整个过程和恶心。

My initial attempt used a single thread and I was getting the same problem, which led me to believe that I need to give the serial port some more time to allow it to send the data before giving it more data on the next loop, because once I've sent data to the serial port I'm back polling the socket very hard. Having said that IOExceptions occur after approximately 30 seconds of operation, possibly with what I'm saying is I should see IOExceptions immediately?

我最初的尝试使用了一个线程,我遇到了同样的问题,这使我相信我需要给串口提供更多的时间来允许它在下一个循环上给它更多的数据之前发送数据,因为一次我已经将数据发送到串口,我正在非常努力地查询套接字。已经说过IOExceptions在大约30秒的操作后发生了,可能我说的是我应该立即看到IOExceptions吗?

My interpretation of the join function, I think, is incorrect, ideally calling readThread.Join from send() would allow read() to sleep while still pumping the COM port, but where I have it seems to put the send() to sleep, which I guess is the calling function?? and not producing the desired result.

我认为我对join函数的解释是不正确的,理想情况下,从send()调用readThread.Join会让read()在仍然抽取COM端口的情况下进入睡眠状态,但是我拥有它似乎让send()进入睡眠状态,我猜是调用函数?并没有产生预期的结果。

Any suggestions would be appreciated. Cheers.

任何建议,将不胜感激。干杯。

2 个解决方案

#1


I've encountered this problem recently as well (and a lot of others have too) - and it's basically a problem with Microsoft's serial port initialization code. I've written a very detailed explanation here if you wish to find out more. I've also suggested a workaround. Hopefully there's enough fuss about this issue such that Microsoft would take notice and fix it asap - perhaps a .NET 4.0 hotfix. This issue has been going on long enough starting .NET 2.0 (first time System.IO.Ports namespace was introduced).

我最近也遇到过这个问题(而且很多其他人也有这个问题) - 这基本上是微软串口初始化代码的问题。如果你想了解更多,我在这里写了一个非常详细的解释。我还提出了一个解决方法。希望有关于这个问题的大惊小怪,微软会注意并尽快修复它 - 也许是.NET 4.0修补程序。这个问题已经持续了很长时间,从.NET 2.0开始(第一次引入了System.IO.Ports命名空间)。

#2


It looks like what you're trying to do is send some data, then wait for a response, then repeat. You're using two threads for this and trying to sync them. I think you only need one thread. First send, then wait for a response, then repeat. This will eliminate your thread sync problems.

看起来你要做的就是发送一些数据,然后等待响应,然后重复。您正在使用两个线程并尝试同步它们。我想你只需要一个帖子。首先发送,然后等待响应,然后重复。这将消除您的线程同步问题。

#1


I've encountered this problem recently as well (and a lot of others have too) - and it's basically a problem with Microsoft's serial port initialization code. I've written a very detailed explanation here if you wish to find out more. I've also suggested a workaround. Hopefully there's enough fuss about this issue such that Microsoft would take notice and fix it asap - perhaps a .NET 4.0 hotfix. This issue has been going on long enough starting .NET 2.0 (first time System.IO.Ports namespace was introduced).

我最近也遇到过这个问题(而且很多其他人也有这个问题) - 这基本上是微软串口初始化代码的问题。如果你想了解更多,我在这里写了一个非常详细的解释。我还提出了一个解决方法。希望有关于这个问题的大惊小怪,微软会注意并尽快修复它 - 也许是.NET 4.0修补程序。这个问题已经持续了很长时间,从.NET 2.0开始(第一次引入了System.IO.Ports命名空间)。

#2


It looks like what you're trying to do is send some data, then wait for a response, then repeat. You're using two threads for this and trying to sync them. I think you only need one thread. First send, then wait for a response, then repeat. This will eliminate your thread sync problems.

看起来你要做的就是发送一些数据,然后等待响应,然后重复。您正在使用两个线程并尝试同步它们。我想你只需要一个帖子。首先发送,然后等待响应,然后重复。这将消除您的线程同步问题。