You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python pyserial readline()与C# SerialPort ReadLine()异常排查

C# SerialPort.ReadLine() 无法识别换行符导致冻结的问题分析

问题背景

使用Python pyserial库读取串口输入可正常工作,代码示例:

import serial
port = serial.Serial(port='COM1', baudrate=19200, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)

while 1:
    N = port.in_waiting
    
    if N>4:
        msg = port.readline(N)
        print(list(msg))

但用C#实现相同功能时,ReadLine()无法识别换行符\n,程序出现冻结现象;使用Read()则可正常读取数据,且已确认两端串口参数设置一致。C#代码示例:

串口初始化代码:

port = new SerialPort("COM1");
port.BaudRate = baudRate;
port.DataBits = 8;
port.Parity = Parity.None;
port.StopBits = StopBits.One;
port.ReadTimeout = SerialPort.InfiniteTimeout;
port.Handshake = Handshake.None;
port.RtsEnable = false;
port.DtrEnable = false;
port.DataReceived += new SerialDataReceivedEventHandler(DataReceived);

DataReceived事件处理方法:

void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    
    int N = port.BytesToRead;
    if (N > 4)
    {
         string line = port.ReadLine();
    }
}

问题原因

  1. 换行符处理逻辑差异

    • pyserial的readline(N):默认以\n作为结束符,且当传入参数N时,会最多读取N个字节,即使未遇到换行符也会返回已读取的内容,不会无限阻塞。
    • C#的SerialPort.ReadLine():默认以\r\n作为结束符,且在设置InfiniteTimeout的情况下,会一直阻塞直到预设的换行符出现,若串口数据仅包含\n而无\r,就会无限等待导致程序冻结。
  2. 读取逻辑的差异
    Python代码中先检查in_waiting>4再调用readline(N),相当于做了预判断,且readline(N)不会无限等待;而C#中DataReceived事件触发后,调用ReadLine()时,该方法不关心当前BytesToRead的数量,只等待换行符,因此即使当前有数据但未出现换行符,也会无限阻塞。

解决方案

方案一:修改NewLine属性匹配换行符

将C# SerialPort的NewLine设置为\n,让ReadLine()以\n作为结束符:

port.NewLine = "\n";

方案二:手动读取字节并处理换行

模仿Python的逻辑,先读取当前可用的所有字节,再自行拆分换行符:

void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    int N = port.BytesToRead;
    if (N > 4)
    {
        byte[] buffer = new byte[N];
        port.Read(buffer, 0, N);
        string receivedData = Encoding.ASCII.GetString(buffer);
        // 按\n拆分数据
        string[] lines = receivedData.Split(new[] {'\n'}, StringSplitOptions.RemoveEmptyEntries);
        foreach (var line in lines)
        {
            // 处理每一行数据
        }
    }
}

方案三:设置合理的超时时间

若必须使用ReadLine(),避免设置InfiniteTimeout,给一个合理的超时值,并捕获超时异常:

port.ReadTimeout = 100; // 设置100毫秒超时
void DataReceived(object sender, SerialDataReceivedEventArgs e)
{
    int N = port.BytesToRead;
    if (N > 4)
    {
        try
        {
            string line = port.ReadLine();
            // 处理数据
        }
        catch (TimeoutException)
        {
            // 处理超时情况
        }
    }
}

内容的提问来源于stack exchange,提问作者wenhoo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 23:20:42