0

ソケットからデータを読み取り、データから情報 (2 つの整数) を抽出し、抽出した情報をシリアル ポートから送信する小さなアプリケーションを作成しようとしています。

アイデアは、それを開始し、そのまま続行する必要があるということです。要するに、それは機能しますが、長くは機能しません。一貫して短い期間の後、IOExceptions を受け取り始め、ソケットの受信バッファーがいっぱいになります。

スレッド フレームワークは、MSDN のシリアル ポートの例から取られています。

send() の遅延、readThread.Join() は、read() を遅延させて、シリアル ポートの割り込み処理を発生させるための努力ですが、結合機能を誤解していると思います。プロセスをより効果的に同期するか、ソケットからデータが入ってくるときにデータを破棄する必要があります。これで問題ありません。整数データはパンチルト ユニットを制御しており、1 秒間に 4 回でも問題ないと思いますが、どのように達成するのが最善かはわかりません。どんなアイデアでも大歓迎です。

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

アップデート:

返信ありがとうございます。

私がやろうとしているのは、データのソケットをポーリングすることです。それが処理されてシリアルポートに送信される場合は、ソケットをポーリングし続け、このプロセス全体をうんざりさせて繰り返します。

私の最初の試みは単一のスレッドを使用しましたが、同じ問題が発生していました。そのため、次のループでさらにデータを送信する前に、シリアルポートにデータを送信できるようにするために、もう少し時間を与える必要があると思いました。シリアルポートにデータを送信しましたが、ソケットを非常に激しくポーリングしています。約 30 秒の操作の後に IOExceptions が発生すると言いましたが、おそらく私が言っているのは、IOExceptions をすぐに見る必要があるということでしょうか?

join 関数の私の解釈は間違っていると思います。理想的には、send() から readThread.Join を呼び出すと、COM ポートをポンピングしながら read() をスリープさせることができますが、send() をスリープ状態にしているようです。 、私は呼び出し関数だと思いますか?? 望ましい結果が得られません。

任意の提案をいただければ幸いです。乾杯。

4

2 に答える 2

2

私も最近この問題に遭遇しました (そして、他の多くの人も同様です)。これは基本的に、Microsoft のシリアル ポート初期化コードの問題です。詳細を知りたい場合は、ここに非常に詳細な説明を書いています。回避策も提案しました。うまくいけば、Microsoft がこの問題に注意を払い、できるだけ早く修正する (おそらく .NET 4.0 ホットフィックス) ように、この問題について十分な議論がなされることを願っています。この問題は、.NET 2.0 (初めて System.IO.Ports 名前空間が導入されたとき) から十分長く続いています。

于 2010-07-05T00:23:25.287 に答える
1

あなたがやろうとしているのは、データを送信し、応答を待ってから繰り返すことです。これには 2 つのスレッドを使用し、それらを同期しようとしています。必要なスレッドは 1 つだけだと思います。最初に送信し、応答を待ってから繰り返します。これにより、スレッド同期の問題が解消されます。

于 2009-06-10T13:35:39.487 に答える