18

私はオープンで、イベントSerialPortを通じてデータを受け取ります。DataReceived

SerialPortが切断されたかどうかを検出する方法はありますか?

ErrorReceivedとイベントを試しましたPinChangedが、運がありませんでした。

それに加えて、SerialPort.IsOpen物理的に切断されたときにtrueを返します。

4

10 に答える 10

16

USBシリアルポートは大きな苦痛です。たとえば、この質問を参照してください。それが本当に.NET4.0で修正されたかどうかはわかりませんが、当時、私は次のようなものでプログラム全体をクラッシュさせる切断の問題に対処しようとしました。

public class SafeSerialPort : SerialPort
{
    private Stream theBaseStream;

    public SafeSerialPort(string portName, int baudRate, Parity parity, int dataBits, StopBits stopBits)
        : base(portName, baudRate, parity, dataBits, stopBits)
    {

    }

    public new void Open()
    {
        try
        {
            base.Open();
            theBaseStream = BaseStream;
            GC.SuppressFinalize(BaseStream);
        }
        catch
        {

        }
    }

    public new void Dispose()
    {
        Dispose(true);
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing && (base.Container != null))
        {
            base.Container.Dispose();               
        }
        try
        {
            if (theBaseStream.CanRead)
            {
                theBaseStream.Close();
                GC.ReRegisterForFinalize(theBaseStream);
            }
        }
        catch
        {
            // ignore exception - bug with USB - serial adapters.
        }
        base.Dispose(disposing);
    }
}

私がこれを採用した人にはお詫びしますが、コードにそれを書き留めなかったようです。この問題は、シリアルポートが消えた場合に.NETが基になるストリームをどのように処理したかに起因しているようです。シリアルポートが切断された後、ストリームを閉じることができなかったようです。

私が使用したもう1つの戦略は、シリアル通信部分だけを実行し、メインプログラムが接続するWCFサービスを公開する小さなプログラムを作成することでした。そうすれば、USBシリアルアダプタがフレークアウトして通信プログラムがクラッシュしたときに、メインプログラムから自動的に再起動できます。

最後に、特にUSBシリアルアダプタの場合、偶発的な切断の問題全体を回避するために、ロックUSBポートを販売した人がいない理由がわかりません。

于 2012-11-16T15:46:32.533 に答える
3

問題は、メソッドが実行されたときにIsOpenのみ値が戻されることです。falseClose

WM_DEVICECHANGEメッセージをキャプチャして使用してみてください。

http://msdn.microsoft.com/en-us/library/windows/desktop/aa363480(v=vs.85).aspx

于 2012-11-16T01:56:17.463 に答える
2

また、USB-Serialアダプターが切断されるとすぐに、処理できない例外(およびコードで問題を検出/回避できない)の問題に直面しました。MatttBurlandのソリューションが機能していることを確認できます。

簡略化されたバージョン:

class SafeSerialPort : SerialPort {
    public new void Open() {
        if (!base.IsOpen) {
            base.Open();
            GC.SuppressFinalize(this.BaseStream);
        }
    }

    public new void Close() {
        if (base.IsOpen) {
            GC.ReRegisterForFinalize(this.BaseStream);
            base.Close();   
        }           
    }

    protected override void Dispose(bool disposing) {
        try {
            base.Dispose(disposing);
        } catch (Exception ex) {
            Debug.WriteLine(ex.Message);
        }

    }
}
于 2012-11-23T11:12:51.290 に答える
1

接続しているデバイスがCDピンを使用している場合は、その変化を監視できます(フロー制御を使用しているデバイスによっては、他のピンが適用される場合があります)。そうでない場合、これを行うための決定的な方法は実際にはありません。

接続されたデバイスの予想される動作に応じて、タイムアウトまたはある種の維持を実装することをお勧めします。

于 2012-11-16T15:54:36.737 に答える
1

まだこの問題に直面している人のために更新してください。いくつかのポイント...

  1. 「USBデバイスを切断しないでください」とユーザーに伝えるのは無駄であり、関係者全員を悩ませます。私たちは彼らがそうしないことを望んでいますが、私たちのプログラムが実行されている間、彼らがデバイスをヤンクアウトすることを知っています...
  2. 以前のバージョンのフレームワークSerialPort.GetPortNames()yankですぐに更新しましたが、4.7は開いているポートのリストを更新しません。このリストの変更をチェックするバックグラウンドスレッドがあります(上記のように)。これは以前はうまく機能していましたが、現在は機能していません...
  3. このフレームワークの変更(バグ?)のために、テスト用にチェックスレッドを更新しましたSerialPort.IsOpen()。これは、4.7で、ユーザーがデバイスをヤンクアウトするとすぐにデバイスが閉じたことを報告します。WM_DEVICECHANGEyankですぐにメッセージが表示されますが、このアプリでは、バックグラウンドスレッドでテストする方が簡単ですSerialPort.IsOpen()
于 2020-08-15T21:20:58.933 に答える
0

私はこの問題を単純なバックグラウンドワーカーで解決しました。現在のすべてのポートを継続的にチェック/アレイに設定し、新しいポートが自分のports-arrayと異なる場合は、これら2つのアレイから変更されたポートを取得します。

例:

// global variable
List<string> oldPorts = new List<string>();    // contains all connected serial ports

private void bgw_checkSerialPorts_DoWork(object seder, DoWorkEventArgs e)
{
    while (true)
    {
        string[] currentPorts = SerialPort.GetPortNames();    // get all connected serial ports
        string[] diffPorts = currentPorts.Except(oldPorts.ToArray());    // get the differences between currentPorts[] and oldPorts-list

        if (diffPorts.Length > 0)
        {
            // iterate all changed ports
            for (int i = 0; i < diff.Length; i++)
            {
                // check if changed port was in old list
                if (oldPorts.Contains(diff[i]))
                {
                    // port in diff[] was removed
                }
                else
                {
                    // port in diff[] is a new device
                }
            }
        }

        oldPorts = currentPorts.ToList();   // update oldPortlist

        // check every 100ms
        Thread.Sleep(100);
    }
}
于 2016-01-25T10:06:46.990 に答える
0

C#SerialPort.CDHoldingフラグを使用します。

したがって、開ループと読み取りループの前に、ブール値をlastCDHoldingフラグに保存します。

test SerialPort.CDHolding!= lastCDHoldingを読んだ後、変更をトラップするか、SerialPort.CDHoldin==falseをテストしてポートが閉じられたことを検出します。

于 2017-12-05T00:17:33.453 に答える
0

私はRFIDデバイスでも同じ問題を抱えていました。
ダミーデータを送信することで、USBの取り外しを検出することができます。

通常、RFIDからデータを受信するだけで済みますが、(私の場合は)毎秒データを送信しても問題はありません。
USBケーブルが切断されると、serialPort.Writeは例外をスローします。
次に、ポートをすぐに閉じる必要があります。そうしないと、プログラムがハングします。

bool verify_connection()
{
    try
    {
        if (serialport.isOpen)
        {
            serialport.WriteLine("Dummy");
        }
    }
    catch (Exception ex)
    {
        serialport.Close();
    }
    return serialport.isOpen;
}

.NETCore3.1でテスト済み

于 2021-08-15T07:03:59.870 に答える
0

私は同じ問題に直面していました。何度か試した後、を使って欲しいものを手に入れましたSerialPort.DsrHolding

USBケーブルが引っ張られるとすぐにfalseに戻ります。これが失敗する可能性のある他の条件を私は知りません。しかし、これは私にとってはうまくいきました。

于 2021-12-14T17:16:21.010 に答える
0

Jebのコードを編集してこのソリューションを入手しました。私は常にそのような場合のバックグラウンドタイマーを持っています(ただし、Comportを接続するときに開始することもできます)Comportを接続するとき、bool "canDisconnect"をtrueに設定しました。これにより、作業を常に完璧にできました。

    bool canDisconnect = false;


    private void tmrBackgroundTick_Tick(object sender, EventArgs e)
    {
        if (canDisconnect == true ){ 
        //Automatic disconnect program if Comport is removed 
            try
            {
                 ComPort.WriteLine("test");
                
            }
            catch (Exception ex)
            {
                disconnect();
                canDisconnect = false;
            }
        
        }
    }
于 2021-12-24T09:24:00.453 に答える