最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

C#實(shí)現(xiàn)串口通信的四種靈活策略和避坑指南

 更新時(shí)間:2026年01月06日 09:30:20   作者:小碼編匠  
這篇文章主要為大家詳細(xì)介紹了C#實(shí)現(xiàn)串口通信的四種靈活策略和避坑的相關(guān)知識(shí),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下

前言

工業(yè)控制、物聯(lián)網(wǎng)設(shè)備通信中,是否遇到過(guò)這樣的場(chǎng)景:向設(shè)備發(fā)送一個(gè)簡(jiǎn)單的查詢指令,卻發(fā)現(xiàn)返回的數(shù)據(jù)總是"分批到達(dá)"?明明應(yīng)該收到完整的20字節(jié)響應(yīng),卻只能收到幾個(gè)零散的數(shù)據(jù)包?

別急,這不是你的代碼有問(wèn)題!

這是串口通信中最常見(jiàn)的"分包接收"現(xiàn)象。設(shè)備可能一次發(fā)送10字節(jié),下一次發(fā)送剩余的10字節(jié),而我們的程序卻不知道什么時(shí)候才算接收完成。

今天我們就來(lái)徹底解決這個(gè)讓無(wú)數(shù) C# 開(kāi)發(fā)頭疼的問(wèn)題!

為什么會(huì)分包接收

根本原因

串口通信是異步的,數(shù)據(jù)傳輸會(huì)受到以下因素影響:

硬件緩沖區(qū)大小限制

設(shè)備處理速度差異

網(wǎng)絡(luò)延遲(對(duì)于串口轉(zhuǎn)以太網(wǎng)設(shè)備)

系統(tǒng)調(diào)度

這些因素導(dǎo)致原本連續(xù)的數(shù)據(jù)流被 操作系統(tǒng)或中間設(shè)備拆分成多個(gè)小塊,逐次送達(dá)應(yīng)用程序。

傳統(tǒng)方案的痛點(diǎn)

// ? 錯(cuò)誤示例:只能收到第一包數(shù)據(jù)
serialPort.Write(command, 0, command.Length);
Thread.Sleep(100); // 固定等待時(shí)間
byte[] buffer = new byte[1024];
int count = serialPort.Read(buffer, 0, 1024); // 可能只讀到部分?jǐn)?shù)據(jù)

這種寫(xiě)法的問(wèn)題包括:

固定等待時(shí)間不可靠

無(wú)法判斷數(shù)據(jù)是否接收完整

容易丟失后續(xù)數(shù)據(jù)包

四種靈活接收策略

為應(yīng)對(duì)不同應(yīng)用場(chǎng)景,我們?cè)O(shè)計(jì)了以下四種策略:

方案一:數(shù)據(jù)間隔超時(shí)判斷(?推薦)

適用場(chǎng)景:不知道數(shù)據(jù)長(zhǎng)度,但設(shè)備發(fā)送完畢后會(huì)有明顯時(shí)間間隔。

public byte[] SendQueryWithGapTimeout(byte[] command, int gapTimeoutMs = 100, int maxWaitMs = 3000)
{
    // 清空緩沖區(qū)并開(kāi)始接收
    lock (bufferLock)
    {
        receivedBuffer.Clear();
        isWaitingForResponse = true;
        lastReceiveTime = DateTime.Now;
    }
    // 發(fā)送指令
    serialPort.Write(command, 0, command.Length);
    
    DateTime startTime = DateTime.Now;
    
    while ((DateTime.Now - startTime).TotalMilliseconds < maxWaitMs)
    {
        Thread.Sleep(10);
        
        lock (bufferLock)
        {
            // ?? 關(guān)鍵邏輯:有數(shù)據(jù)且間隔超時(shí)則認(rèn)為接收完成
            if (receivedBuffer.Count > 0 && 
                (DateTime.Now - lastReceiveTime).TotalMilliseconds > gapTimeoutMs)
            {
                isWaitingForResponse = false;
                return receivedBuffer.ToArray();
            }
        }
    }
    
    return null;
}

實(shí)際業(yè)務(wù)中,這個(gè)能解決大部分問(wèn)題。

方案二:結(jié)束符判斷

適用場(chǎng)景:數(shù)據(jù)以特定字符結(jié)尾(如 \r\n、\0 等)。

public byte[] SendQueryWithEndMarker(byte[] command, byte[] endMarker, int maxWaitMs = 3000)
{
    // ... 發(fā)送邏輯相同 ...
    
    while ((DateTime.Now - startTime).TotalMilliseconds < maxWaitMs)
    {
        lock (bufferLock)
        {
            if (receivedBuffer.Count >= endMarker.Length)
            {
                // ?? 檢查緩沖區(qū)末尾是否包含結(jié)束標(biāo)記
                bool foundEndMarker = true;
                for (int i = 0; i < endMarker.Length; i++)
                {
                    if (receivedBuffer[receivedBuffer.Count - endMarker.Length + i] != endMarker[i])
                    {
                        foundEndMarker = false;
                        break;
                    }
                }
                
                if (foundEndMarker)
                {
                    return receivedBuffer.ToArray();
                }
            }
        }
    }
}

方案三:協(xié)議幀結(jié)構(gòu)判斷

適用場(chǎng)景:數(shù)據(jù)有固定幀頭和長(zhǎng)度字段(如 Modbus 協(xié)議)。

public byte[] SendQueryWithFrameProtocol(byte[] command, byte frameHeader, int lengthFieldOffset, int lengthFieldSize = 1)
{
    // ... 發(fā)送邏輯 ...
    
    while (/* 超時(shí)檢查 */)
    {
        lock (bufferLock)
        {
            if (receivedBuffer.Count > lengthFieldOffset + lengthFieldSize)
            {
                // 檢查幀頭
                if (receivedBuffer[0] == frameHeader)
                {
                    // ?? 從長(zhǎng)度字段獲取數(shù)據(jù)長(zhǎng)度
                    int dataLength = lengthFieldSize == 1 ? 
                        receivedBuffer[lengthFieldOffset] : 
                        (receivedBuffer[lengthFieldOffset] << 8) | receivedBuffer[lengthFieldOffset + 1];
                    
                    int expectedFrameLength = lengthFieldOffset + lengthFieldSize + dataLength;
                    
                    if (receivedBuffer.Count >= expectedFrameLength)
                    {
                        return receivedBuffer.Take(expectedFrameLength).ToArray();
                    }
                }
            }
        }
    }
}

方案四:組合策略(??推薦)

最靈活的方案,同時(shí)使用多種判斷條件:

public byte[] SendQueryWithCombinedStrategy(byte[] command,
    int gapTimeoutMs = 100,     // 數(shù)據(jù)間隔超時(shí)
    byte[] endMarker = null,    // 結(jié)束標(biāo)記  
    int? maxLength = null,      // 最大長(zhǎng)度限制
    int maxWaitMs = 3000)       // 總超時(shí)時(shí)間
{
    // ... 發(fā)送邏輯 ...
    
    while (/* 總超時(shí)檢查 */)
    {
        lock (bufferLock)
        {
            if (receivedBuffer.Count == 0) continue;
            
            // ?? 條件1:達(dá)到最大長(zhǎng)度限制
            if (maxLength.HasValue && receivedBuffer.Count >= maxLength.Value)
                return receivedBuffer.ToArray();
            
            // ?? 條件2:發(fā)現(xiàn)結(jié)束標(biāo)記
            if (endMarker != null && /* 檢查結(jié)束標(biāo)記邏輯 */)
                return receivedBuffer.ToArray();
            
            // ?? 條件3:數(shù)據(jù)間隔超時(shí)
            if ((DateTime.Now - lastReceiveTime).TotalMilliseconds > gapTimeoutMs)
                return receivedBuffer.ToArray();
        }
    }
}

核心機(jī)制:數(shù)據(jù)接收事件

所有策略都依賴于統(tǒng)一的數(shù)據(jù)接收事件處理:

private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
{
    if (!isWaitingForResponse) return;
    try
    {
        int bytesToRead = serialPort.BytesToRead;
        if (bytesToRead > 0)
        {
            byte[] buffer = new byte[bytesToRead];
            int bytesRead = serialPort.Read(buffer, 0, bytesToRead);
            lock (bufferLock)
            {
                receivedBuffer.AddRange(buffer);
                lastReceiveTime = DateTime.Now; // ?? 更新最后接收時(shí)間
                Console.WriteLine($"收到數(shù)據(jù)包 ({bytesRead} 字節(jié)): {BitConverter.ToString(buffer, 0, bytesRead)}");
            }
        }
    }
    catch (Exception ex)
    {
        Console.WriteLine($"數(shù)據(jù)接收異常: {ex.Message}");
    }
}

完整代碼

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace AppFlexSerialPort
{
    internal class FlexibleSerialPort
    {
        private SerialPort serialPort;
        private List<byte> receivedBuffer;
        private readonly object bufferLock = new object();
        private Timer timeoutTimer;
        private bool isWaitingForResponse = false;
        private DateTime lastReceiveTime;
        private readonly int dataGapTimeout = 100; // 數(shù)據(jù)間隔超時(shí)時(shí)間(ms)

        public FlexibleSerialPort()
        {
            receivedBuffer = new List<byte>();
        }

        /// <summary>
        /// 初始化串口
        /// </summary>
        public bool InitializePort(string portName = "COM1", int baudRate = 9600,
            Parity parity = Parity.None, int dataBits = 8, StopBits stopBits = StopBits.One)
        {
            try
            {
                serialPort = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                serialPort.ReadTimeout = 1000;
                serialPort.WriteTimeout = 1000;
                serialPort.DataReceived += OnDataReceived;
                serialPort.Open();
                Console.WriteLine($"串口 {portName} 已成功打開(kāi)");
                return true;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"串口初始化失敗: {ex.Message}");
                return false;
            }
        }

        /// <summary>
        /// 方案1: 基于數(shù)據(jù)間隔超時(shí)判斷接收完成
        /// 適用于:不知道數(shù)據(jù)長(zhǎng)度,但設(shè)備發(fā)送完后會(huì)有明顯的時(shí)間間隔
        /// </summary>
        public byte[] SendQueryWithGapTimeout(byte[] command, int gapTimeoutMs = 100, int maxWaitMs = 3000)
        {
            if (serialPort == null || !serialPort.IsOpen)
            {
                Console.WriteLine("串口未打開(kāi)");
                return null;
            }
            lock (bufferLock)
            {
                receivedBuffer.Clear();
                isWaitingForResponse = true;
                lastReceiveTime = DateTime.Now;
            }
            try
            {
                // 發(fā)送查詢指令
                serialPort.Write(command, 0, command.Length);
                Console.WriteLine($"已發(fā)送查詢指令: {BitConverter.ToString(command)}");
                DateTime startTime = DateTime.Now;
                DateTime lastCheckTime = DateTime.Now;
                int lastBufferSize = 0;
                while ((DateTime.Now - startTime).TotalMilliseconds < maxWaitMs)
                {
                    Thread.Sleep(10);
                    lock (bufferLock)
                    {
                        // 如果有數(shù)據(jù)且數(shù)據(jù)間隔超過(guò)指定時(shí)間,認(rèn)為接收完成
                        if (receivedBuffer.Count > 0 &&
                            (DateTime.Now - lastReceiveTime).TotalMilliseconds > gapTimeoutMs)
                        {
                            isWaitingForResponse = false;
                            byte[] result = receivedBuffer.ToArray();
                            Console.WriteLine($"基于間隔超時(shí)判斷接收完成,共收到 {result.Length} 字節(jié)");
                            return result;
                        }
                    }
                }
                // 最大等待時(shí)間超時(shí)
                isWaitingForResponse = false;
                lock (bufferLock)
                {
                    if (receivedBuffer.Count > 0)
                    {
                        byte[] result = receivedBuffer.ToArray();
                        Console.WriteLine($"最大等待時(shí)間超時(shí),收到 {result.Length} 字節(jié)");
                        return result;
                    }
                }
                Console.WriteLine("接收超時(shí),未收到任何數(shù)據(jù)");
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"發(fā)送指令失敗: {ex.Message}");
                isWaitingForResponse = false;
                return null;
            }
        }

        /// <summary>
        /// 方案2: 基于結(jié)束符判斷接收完成
        /// 適用于:數(shù)據(jù)以特定字符或字節(jié)序列結(jié)尾
        /// </summary>
        public byte[] SendQueryWithEndMarker(byte[] command, byte[] endMarker, int maxWaitMs = 3000)
        {
            if (serialPort == null || !serialPort.IsOpen)
            {
                Console.WriteLine("串口未打開(kāi)");
                return null;
            }
            lock (bufferLock)
            {
                receivedBuffer.Clear();
                isWaitingForResponse = true;
            }
            try
            {
                serialPort.Write(command, 0, command.Length);
                Console.WriteLine($"已發(fā)送查詢指令: {BitConverter.ToString(command)}");
                DateTime startTime = DateTime.Now;
                while ((DateTime.Now - startTime).TotalMilliseconds < maxWaitMs)
                {
                    Thread.Sleep(10);
                    lock (bufferLock)
                    {
                        if (receivedBuffer.Count >= endMarker.Length)
                        {
                            // 檢查緩沖區(qū)末尾是否包含結(jié)束標(biāo)記
                            bool foundEndMarker = true;
                            for (int i = 0; i < endMarker.Length; i++)
                            {
                                if (receivedBuffer[receivedBuffer.Count - endMarker.Length + i] != endMarker[i])
                                {
                                    foundEndMarker = false;
                                    break;
                                }
                            }
                            if (foundEndMarker)
                            {
                                isWaitingForResponse = false;
                                byte[] result = receivedBuffer.ToArray();
                                Console.WriteLine($"發(fā)現(xiàn)結(jié)束標(biāo)記,接收完成,共收到 {result.Length} 字節(jié)");
                                return result;
                            }
                        }
                    }
                }
                // 超時(shí)處理
                isWaitingForResponse = false;
                lock (bufferLock)
                {
                    if (receivedBuffer.Count > 0)
                    {
                        byte[] result = receivedBuffer.ToArray();
                        Console.WriteLine($"等待結(jié)束標(biāo)記超時(shí),收到 {result.Length} 字節(jié)");
                        return result;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"發(fā)送指令失敗: {ex.Message}");
                isWaitingForResponse = false;
                return null;
            }
        }

        /// <summary>
        /// 方案3: 基于協(xié)議幀結(jié)構(gòu)判斷接收完成
        /// 適用于:數(shù)據(jù)有固定的幀頭和長(zhǎng)度字段
        /// </summary>
        public byte[] SendQueryWithFrameProtocol(byte[] command, byte frameHeader, int lengthFieldOffset,
            int lengthFieldSize = 1, int maxWaitMs = 3000)
        {
            if (serialPort == null || !serialPort.IsOpen)
            {
                Console.WriteLine("串口未打開(kāi)");
                return null;
            }
            lock (bufferLock)
            {
                receivedBuffer.Clear();
                isWaitingForResponse = true;
            }
            try
            {
                serialPort.Write(command, 0, command.Length);
                Console.WriteLine($"已發(fā)送查詢指令: {BitConverter.ToString(command)}");
                DateTime startTime = DateTime.Now;
                while ((DateTime.Now - startTime).TotalMilliseconds < maxWaitMs)
                {
                    Thread.Sleep(10);
                    lock (bufferLock)
                    {
                        if (receivedBuffer.Count > lengthFieldOffset + lengthFieldSize)
                        {
                            // 檢查幀頭
                            if (receivedBuffer[0] == frameHeader)
                            {
                                // 獲取數(shù)據(jù)長(zhǎng)度
                                int dataLength = 0;
                                if (lengthFieldSize == 1)
                                {
                                    dataLength = receivedBuffer[lengthFieldOffset];
                                }
                                else if (lengthFieldSize == 2)
                                {
                                    dataLength = (receivedBuffer[lengthFieldOffset] << 8) | receivedBuffer[lengthFieldOffset + 1];
                                }
                                int expectedFrameLength = lengthFieldOffset + lengthFieldSize + dataLength;
                                if (receivedBuffer.Count >= expectedFrameLength)
                                {
                                    isWaitingForResponse = false;
                                    byte[] result = receivedBuffer.Take(expectedFrameLength).ToArray();
                                    Console.WriteLine($"根據(jù)幀長(zhǎng)度判斷接收完成,共收到 {result.Length} 字節(jié)");
                                    return result;
                                }
                            }
                        }
                    }
                }
                // 超時(shí)處理
                isWaitingForResponse = false;
                lock (bufferLock)
                {
                    if (receivedBuffer.Count > 0)
                    {
                        byte[] result = receivedBuffer.ToArray();
                        Console.WriteLine($"幀協(xié)議解析超時(shí),收到 {result.Length} 字節(jié)");
                        return result;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"發(fā)送指令失敗: {ex.Message}");
                isWaitingForResponse = false;
                return null;
            }
        }

        /// <summary>
        /// 方案4: 組合策略 - 最靈活的方案
        /// 同時(shí)使用多種判斷條件,任一條件滿足就結(jié)束接收
        /// </summary>
        public byte[] SendQueryWithCombinedStrategy(byte[] command,
            int gapTimeoutMs = 100,
            byte[] endMarker = null,
            int? maxLength = null,
            int maxWaitMs = 3000)
        {
            if (serialPort == null || !serialPort.IsOpen)
            {
                Console.WriteLine("串口未打開(kāi)");
                return null;
            }
            lock (bufferLock)
            {
                receivedBuffer.Clear();
                isWaitingForResponse = true;
                lastReceiveTime = DateTime.Now;
            }
            try
            {
                serialPort.Write(command, 0, command.Length);
                Console.WriteLine($"已發(fā)送查詢指令: {BitConverter.ToString(command)}");
                DateTime startTime = DateTime.Now;
                while ((DateTime.Now - startTime).TotalMilliseconds < maxWaitMs)
                {
                    Thread.Sleep(10);
                    lock (bufferLock)
                    {
                        if (receivedBuffer.Count == 0) continue;
                        // 條件1: 檢查最大長(zhǎng)度限制
                        if (maxLength.HasValue && receivedBuffer.Count >= maxLength.Value)
                        {
                            isWaitingForResponse = false;
                            byte[] result = receivedBuffer.ToArray();
                            Console.WriteLine($"達(dá)到最大長(zhǎng)度限制,接收完成,共收到 {result.Length} 字節(jié)");
                            return result;
                        }
                        // 條件2: 檢查結(jié)束標(biāo)記
                        if (endMarker != null && receivedBuffer.Count >= endMarker.Length)
                        {
                            bool foundEndMarker = true;
                            for (int i = 0; i < endMarker.Length; i++)
                            {
                                if (receivedBuffer[receivedBuffer.Count - endMarker.Length + i] != endMarker[i])
                                {
                                    foundEndMarker = false;
                                    break;
                                }
                            }
                            if (foundEndMarker)
                            {
                                isWaitingForResponse = false;
                                byte[] result = receivedBuffer.ToArray();
                                Console.WriteLine($"發(fā)現(xiàn)結(jié)束標(biāo)記,接收完成,共收到 {result.Length} 字節(jié)");
                                return result;
                            }
                        }
                        // 條件3: 檢查數(shù)據(jù)間隔超時(shí)
                        if ((DateTime.Now - lastReceiveTime).TotalMilliseconds > gapTimeoutMs)
                        {
                            isWaitingForResponse = false;
                            byte[] result = receivedBuffer.ToArray();
                            Console.WriteLine($"數(shù)據(jù)間隔超時(shí),接收完成,共收到 {result.Length} 字節(jié)");
                            return result;
                        }
                    }
                }
                // 最大等待時(shí)間超時(shí)
                isWaitingForResponse = false;
                lock (bufferLock)
                {
                    if (receivedBuffer.Count > 0)
                    {
                        byte[] result = receivedBuffer.ToArray();
                        Console.WriteLine($"最大等待時(shí)間超時(shí),收到 {result.Length} 字節(jié)");
                        return result;
                    }
                }
                return null;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"發(fā)送指令失敗: {ex.Message}");
                isWaitingForResponse = false;
                return null;
            }
        }

        /// <summary>
        /// 數(shù)據(jù)接收事件處理
        /// </summary>
        private void OnDataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (!isWaitingForResponse) return;
            try
            {
                int bytesToRead = serialPort.BytesToRead;
                if (bytesToRead > 0)
                {
                    byte[] buffer = new byte[bytesToRead];
                    int bytesRead = serialPort.Read(buffer, 0, bytesToRead);
                    lock (bufferLock)
                    {
                        receivedBuffer.AddRange(buffer);
                        lastReceiveTime = DateTime.Now; // 更新最后接收時(shí)間
                        Console.WriteLine($"收到數(shù)據(jù)包 ({bytesRead} 字節(jié)): {BitConverter.ToString(buffer, 0, bytesRead)}");
                        Console.WriteLine($"當(dāng)前緩沖區(qū)總計(jì): {receivedBuffer.Count} 字節(jié)");
                    }
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"數(shù)據(jù)接收處理異常: {ex.Message}");
            }
        }

        /// <summary>
        /// 關(guān)閉串口
        /// </summary>
        public void Close()
        {
            try
            {
                isWaitingForResponse = false;
                if (serialPort != null && serialPort.IsOpen)
                {
                    serialPort.Close();
                    Console.WriteLine("串口已關(guān)閉");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"關(guān)閉串口異常: {ex.Message}");
            }
        }

        public static string[] GetAvailablePorts()
        {
            return SerialPort.GetPortNames();
        }
    }
}
namespace AppFlexSerialPort
{
    internal class Program
    {
        static void Main(string[] args)
        {
            FlexibleSerialPort comm = new FlexibleSerialPort();
            try
            {
                if (comm.InitializePort("COM1", 9600))
                {
                    byte[] queryCommand = { 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A };
                    Console.WriteLine("=== 方案1: 基于數(shù)據(jù)間隔判斷 ===");
                    byte[] response1 = comm.SendQueryWithGapTimeout(queryCommand, 150, 3000);
                    Thread.Sleep(1000);
                    Console.WriteLine("\n=== 方案2: 基于結(jié)束符判斷 ===");
                    byte[] endMarker = { 0x0D, 0x0A }; // CR LF
                    byte[] response2 = comm.SendQueryWithEndMarker(queryCommand, endMarker);
                    Thread.Sleep(1000);
                    Console.WriteLine("\n=== 方案3: 基于協(xié)議幀結(jié)構(gòu)判斷 ===");
                    byte[] response3 = comm.SendQueryWithFrameProtocol(queryCommand, 0x01, 2, 1);
                    Thread.Sleep(1000);
                    Console.WriteLine("\n=== 方案4: 組合策略 ===");
                    byte[] response4 = comm.SendQueryWithCombinedStrategy(
                        queryCommand,
                        gapTimeoutMs: 100,           // 數(shù)據(jù)間隔100ms
                        endMarker: new byte[] { 0x0A }, // 或者以LF結(jié)尾
                        maxLength: 50,               // 或者最多50字節(jié)
                        maxWaitMs: 3000              // 最多等待3秒
                    );
                }
                Console.WriteLine("按任意鍵退出...");
                Console.ReadKey();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"程序異常: {ex.Message}");
            }
            finally
            {
                comm.Close();
            }
        }
    }
}

結(jié)果如下: 

性能優(yōu)化與實(shí)踐

關(guān)鍵參數(shù)調(diào)優(yōu)

// ? 推薦配置
int gapTimeoutMs = 100;    // 100-200ms適合大多數(shù)設(shè)備
int maxWaitMs = 3000;      // 總超時(shí)3秒,避免程序卡死
Thread.Sleep(10);          // 輪詢間隔10ms,平衡CPU占用和響應(yīng)速度

線程安全保障

private readonly object bufferLock = new object();
// 所有緩沖區(qū)操作都要加鎖
lock (bufferLock)
{
    receivedBuffer.Clear();
    receivedBuffer.AddRange(buffer);
    // ... 其他緩沖區(qū)操作
}

常見(jiàn)提醒

1、忘記清空緩沖區(qū):每次查詢前必須 receivedBuffer.Clear()

2、超時(shí)時(shí)間設(shè)置不當(dāng):間隔超時(shí)太短會(huì)截?cái)鄶?shù)據(jù),太長(zhǎng)會(huì)影響響應(yīng)速度

3、線程安全問(wèn)題:DataReceived 事件在不同線程中執(zhí)行,必須加鎖保護(hù)

4、資源釋放:程序結(jié)束前記得調(diào)用 Close() 方法

適用場(chǎng)景對(duì)比

方案適用場(chǎng)景優(yōu)點(diǎn)缺點(diǎn)
間隔超時(shí)通用場(chǎng)景簡(jiǎn)單可靠需要調(diào)試最佳間隔時(shí)間
結(jié)束符判斷文本協(xié)議精確判斷需要明確的結(jié)束符
幀結(jié)構(gòu)判斷二進(jìn)制協(xié)議最精確需要了解協(xié)議細(xì)節(jié)
組合策略復(fù)雜場(chǎng)景最靈活代碼稍復(fù)雜

總結(jié)

1、選擇合適的策略:對(duì)于90%的場(chǎng)景,數(shù)據(jù)間隔超時(shí)判斷就足夠了

2、參數(shù)調(diào)優(yōu)很重要:100-200ms 的間隔超時(shí)是經(jīng)驗(yàn)值,需要根據(jù)實(shí)際設(shè)備調(diào)整

3、組合策略是王道:當(dāng)單一策略無(wú)法滿足需求時(shí),組合策略提供了最大的靈活性

通過(guò)本文介紹的四種策略,開(kāi)發(fā)者可以根據(jù)具體通信協(xié)議靈活選擇最適合的接收方式,徹底告別"分包接收"帶來(lái)的困擾。

到此這篇關(guān)于C#實(shí)現(xiàn)串口通信的四種靈活策略和避坑指南的文章就介紹到這了,更多相關(guān)C#串口通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

神木县| 静宁县| 吉林省| 白山市| 永顺县| 长海县| 林芝县| 桐城市| 四平市| 孟村| 龙州县| 平定县| 清徐县| 松滋市| 禹城市| 大石桥市| 通海县| 河间市| 定西市| 蓬溪县| 黄浦区| 扶沟县| 张家口市| 山东省| 长沙市| 大埔县| 嵊泗县| 德州市| 阳新县| 宁远县| 郁南县| 怀化市| 辉县市| 前郭尔| 台北市| 绍兴市| 磐安县| 灌南县| 河间市| 深泽县| 嘉定区|