编写时的线程串口IOException

时间:2009-06-10 13:25:03

标签: c# multithreading serial-port ioexception writing

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

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

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

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"); }
            }
        }
    }
}

更新:

感谢Jon的回应。

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

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

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

任何建议将不胜感激。欢呼声。

2 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:1)

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