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(); } }
问题原因
换行符处理逻辑差异
- pyserial的
readline(N):默认以\n作为结束符,且当传入参数N时,会最多读取N个字节,即使未遇到换行符也会返回已读取的内容,不会无限阻塞。 - C#的
SerialPort.ReadLine():默认以\r\n作为结束符,且在设置InfiniteTimeout的情况下,会一直阻塞直到预设的换行符出现,若串口数据仅包含\n而无\r,就会无限等待导致程序冻结。
- pyserial的
读取逻辑的差异
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
相关产品推荐
相关产品推荐

