последовательный порт IOException при записи - PullRequest
0 голосов
/ 10 июня 2009

Я пытаюсь написать небольшое приложение, которое просто читает данные из сокета, извлекает некоторую информацию (два целых числа) из данных и отправляет извлеченную информацию на последовательный порт.

Идея в том, что это должно начаться и просто продолжать. Короче, работает, но ненадолго. После непродолжительного периода времени я начинаю получать IOExceptions и буфер приема сокета забивается.

Структура потока была взята из примера последовательного порта MSDN.

Задержка в send (), readThread.Join (), является попыткой задержать read (), чтобы дать возможность обработки прерывания последовательного порта, но я думаю, что я неправильно интерпретировал функцию соединения. Мне нужно либо более эффективно синхронизировать процессы, либо выбрасывать некоторые данные, когда они поступают из сокета, что было бы хорошо. Целочисленные данные управляют устройством панорамирования и наклона, и я уверен, что четыре раза в секунду будет приемлемо, но не уверен в том, как добиться наилучшего результата, любые идеи будут высоко оценены, ура.

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

ОБНОВЛЕНИЕ:

Спасибо за ответ, Джон.

То, что я пытаюсь сделать, это опросить сокет для данных, если они там обрабатываются и отправляются на последовательный порт , в противном случае продолжайте опрашивать сокет , повторяя весь этот процесс до тошноты.

Моя первоначальная попытка использовала один поток, и у меня возникла та же проблема, из-за чего я поверил, что мне нужно дать последовательному порту еще немного времени, чтобы он мог отправлять данные, прежде чем дать ему больше данных в следующем цикле. потому что, как только я отправил данные на последовательный порт, я снова очень сильно опрашиваю сокет. Сказав, что исключения IOException возникают примерно через 30 секунд работы, возможно, с тем, что я говорю, я должен немедленно увидеть исключения IOExceptions?

Моя интерпретация функции соединения, я думаю, неверна, в идеале вызов readThread.Join из send () позволил бы read () спать, все еще перекачивая COM-порт, но там, где он у меня, кажется, помещен send ( ) спать, который, я думаю, является вызывающей функцией ?? и не дает желаемого результата.

Любые предложения будут оценены. Приветствия.

Ответы [ 2 ]

2 голосов
/ 05 июля 2010

Я также столкнулся с этой проблемой в последнее время (и многие другие тоже) - и это в основном проблема с кодом инициализации последовательного порта Microsoft. Я написал очень подробное объяснение здесь , если вы хотите узнать больше. Я также предложил обходной путь. Надеемся, что этой проблемы будет достаточно, так что Microsoft заметит и исправит ее как можно быстрее - возможно, исправление .NET 4.0. Эта проблема продолжалась достаточно долго, начиная с .NET 2.0 (впервые было представлено пространство имен System.IO.Ports).

1 голос
/ 10 июня 2009

Похоже, что вы пытаетесь сделать, это отправить некоторые данные, затем ждать ответа, а затем повторите. Вы используете два потока для этого и пытаетесь синхронизировать их. Я думаю, вам нужна только одна нить. Сначала отправьте, затем дождитесь ответа, затем повторите. Это устранит проблемы с синхронизацией потоков.

...