首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C# SerialPort 多次短時間接收資料處理策略

     編輯:程式設計綜合問答

問題場景

串口裝置可能單次發送完整封包,也可能在極短時間內分多次發送(如斷續傳輸)。需區分「單次完整封包」與「多次碎片封包」並分別處理。

核心建議:協議層面加入封包頭/長度/校驗

單純依靠「時間間隔」判斷極不穩定(作業系統排程、緩衝區、傳輸延遲皆會干擾)。標準做法是在應用層協議中定義明確的幀結構:

典型幀格式

[帧头 2 bytes] [长度 2 bytes] [命令 1 byte] [数据 N bytes] [校验 1 byte] [帧尾 2 bytes]
例:0xAA 0x55 0x00 0x0A 0x01 [data...] 0xXX 0x0D 0x0A

接收邏輯實作 (生產者-消費者模式)

1. 緩衝區累積

private readonly List<byte> _buffer = new List<byte>();
private readonly object _lock = new object();

2. DataReceived 事件只負責存入緩衝區

private void Port_DataReceived(object sender, SerialDataReceivedEventArgs e) {
    int count = serialPort.BytesToRead;
    byte[] tmp = new byte[count];
    serialPort.Read(tmp, 0, count);
    lock (_lock) {
        _buffer.AddRange(tmp);
    }
    // 通知處理執行緒
    _dataEvent.Set(); 
}

3. 專用執行緒解析完整幀

private void ProcessLoop() {
    while (_running) {
        _dataEvent.WaitOne(50);
        List<byte> frame;
        lock (_lock) {
            frame = TryExtractFrame(_buffer); // 從緩衝區提取一個完整幀
            if (frame == null) continue;
            _buffer.RemoveRange(0, frame.Count);
        }
        HandleFrame(frame); // 交給業務邏輯
    }
}

private List<byte> TryExtractFrame(List<byte> buf) {
    // 1. 尋找帧头
    int start = buf.FindIndex(b => b == 0xAA);
    if (start < 0) return null;
    if (start > 0) { buf.RemoveRange(0, start); } // 丟棄雜訊

    // 2. 長度檢查
    if (buf.Count < 4) return null; // 至少 帧头+长度
    int len = (buf[2] << 8) | buf[3]; // 假設大端序
    int totalLen = 2 + 2 + 1 + len + 1 + 2; // 完整幀長度

    if (buf.Count < totalLen) return null; // 資料未完整

    // 3. 校驗帧尾、校驗和
    if (buf[totalLen-2] != 0x0D || buf[totalLen-1] != 0x0A) {
        buf.RemoveAt(0); // 帧头錯誤,移除一個字節重試
        return null;
    }
    // TODO: 校驗和驗證

    return buf.GetRange(0, totalLen);
}

優勢

  • 不依賴時間間隔,穩健處理「單次/多次/碎片/粘包」各種情況。
  • 緩衝區與解析分離,執行緒安全。
  • 易於擴展:支援多種命令、分片重組、錯誤重傳。

若無法修改協議(舊設備)

若必須靠時間判斷,可設定「閒置超時」:收到資料後啟動 Timer (如 50ms),超時未再收到資料視為一個完整邏輯封包。但此法不可靠,僅作臨時方案。

總結

「在協議中加入封包頭、長度、校驗」是處理串口資料分包/粘包的工業標準做法,請優先推動硬體端協議升級。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved