我有两个应用程序通过 TCP/IP 连接进行交互;现在我需要他们能够通过串行连接进行交互。
套接字 IO 和串行 IO 之间存在一些差异,这使得移植没有我希望的那么简单。
区别之一是关于发送/写入超时的语义以及应用程序可能对成功通过连接的数据量做出的假设。知道这个数量后,应用程序也知道它需要在以后选择传输哪些剩余数据。
套接字发送
像 socket.send(string) 这样的调用可能会产生以下结果:
- 整个字符串已被 TCP/IP 堆栈接受,并返回字符串的长度。
- 字符串的一部分已被 TCP/IP 堆栈接受,并返回该部分的长度。应用程序可以稍后传输字符串的其余部分。
- 如果套接字配置为使用超时并且发送方使用数据淹没了连接,则会引发 socket.timeout 异常。这意味着(如果我理解正确的话) TCP/IP 堆栈没有接受字符串的任何字节,因此应用程序可能会稍后尝试发送整个字符串。
- 由于连接的一些问题,引发了 socket.error 异常。
PySerial.Serial.write
PySerial API 文档对 Serial.write(string) 进行了如下说明:
write(data)
Parameters:
data – Data to send.
Returns:
Number of bytes written.
Raises
SerialTimeoutException:
In case a write timeout is configured for the port and the time is exceeded.
Changed in version 2.5: Write returned None in previous versions.
这个规范给我留下了一些不确定的问题:
- 在哪些情况下,“write(data)”返回的写入字节数可能少于数据的长度?是否只能在非阻塞模式下(writeTimeout = 0)?
- 如果我使用正的 writeTimeout 并且引发了 SerialTimeoutException,我怎么知道有多少字节进入了连接?
我还观察到一些我没想到的 serial.write 行为。
该测试尝试通过慢速连接发送长字符串。发送端口使用 9600,8,N,1 并且没有流控。接收端口也已打开,但没有尝试从中读取数据。
- 如果 writeTimeout 为正但不够大,则发送者预期会收到 SerialTimeoutException。
- 如果 writeTimeout 设置得足够大,则发送方预期会成功写入所有数据(接收方不关心读取,我们也不关心)。
- 如果 writeTimeout 设置为 None,则发送方会意外获得 SerialTimeoutException 而不是阻塞,直到所有数据都断开连接。我错过了什么吗?
我不知道这种行为是否典型。万一这很重要,我在 Windows 7 64 位上使用 PySerial 进行实验,使用两个 USB-to-COM 适配器通过零调制解调器电缆连接;该设置似乎是可操作的,因为 Tera Term 的两个实例可以通过它相互交谈。
了解人们是否以除中止连接和通知用户问题之外的任何方式处理串行写入超时将很有帮助。
由于我目前不知道在超时发生之前写入的数据量,因此我正在考虑使用非阻塞写入并将类套接字超时语义保持在该级别之上的解决方法。我不希望这是一个非常有效的解决方案 (:-)),但幸运的是,我的应用程序交换相对不频繁和短消息,因此性能应该在可接受的范围内。
[编辑]
仔细研究非阻塞串行写入
我写了一个简单的程序来看看我是否理解非阻塞写是如何工作的:
import serial
p1 = serial.Serial("COM11") # My USB-to-COM adapters appear at these high port numbers
p2 = serial.Serial("COM12")
message = "Hello! " * 10
print "%d bytes in the whole message: %r" % (len(message), message)
p1.writeTimeout = 0 # enabling non-blocking mode
bytes_written = p1.write(message)
print "Written %d bytes of the message: %r" % (bytes_written, message[:bytes_written])
print "Receiving back %d bytes of the message" % len(message)
message_read_back = p2.read(len(message))
print "Received back %d bytes of the message: %r" % (len(message_read_back), message_read_back)
p1.close()
p2.close()
我得到的输出是这样的:
整个消息中的 70 个字节:'你好!你好!你好!你好!你好!你好!你好!你好!你好!你好!'
写入 0 字节的消息:''
接收回 70 字节的消息
接收回 70 字节的消息:'你好!你好!你好!你好!你好!你好!你好!你好!你好!你好!'
我很困惑:发送者认为没有数据发送,但接收者得到了一切。我必须在这里遗漏一些非常基本的东西......
非常欢迎任何意见/建议/问题!