我有两个应用程序通过TCP / IP连接进行交互;现在我需要他们能够通过串行连接进行交互。
套接字IO和串行IO之间存在一些差异,这使得移植不如我希望的那么简单。
其中一个区别在于发送/写入超时的语义以及应用程序可能对成功传递给连接的数据量的假设。知道了这个数量,应用程序也知道它应该选择后需要传输哪些剩余数据。
像socket.send(string)之类的调用可能会产生以下结果:
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.
这个规范给我留下了一些不确定的问题:
我还观察到一些我没想到的serial.write行为。
测试尝试通过慢速连接发送长字符串。发送端口使用9600,8,N,1,无流量控制。接收端口也是打开的,但没有尝试从中读取数据。
我不知道这种行为是否典型。 如果重要的话,我使用通过零调制解调器电缆连接的两个USB到COM适配器在Windows 7 64位上试验PySerial;该设置似乎是可操作的,因为Tera Term的两个实例可以相互通信。
了解人们是否以除了中止连接和通知用户问题之外的任何方式处理串行写入超时将会很有帮助。
由于我目前不知道在超时发生之前写入的数据量,我正在考虑使用非阻塞写入的解决方法,并在该级别上维护类似套接字的超时语义。我不认为这是一个非常有效的解决方案(:-)),但幸运的是我的应用程序交换相对不频繁和短消息,因此性能应该在可接受的范围内。
[EDITED]
我写了一个简单的程序,看看我是否理解非阻塞写的工作方式:
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个字节的消息:'您好!你好!你好!你好!你好!你好!你好!你好!你好!你好! '
我很困惑:发送者认为没有数据发送但是接收者得到了所有数据。我必须在这里遗漏一些非常基本的东西......
非常欢迎任何意见/建议/问题!
答案 0 :(得分:1)
由于没有记录,让我们来看看源代码。我只关注POSIX和Win32实现,但至少在这两个平台上显而易见:
write(data)
返回的字节数少于数据长度,超时或其他时,有无情况;它总是要么返回完整的len(data)
,要么引发异常。writeTimeout
并且SerialTimeoutException
被引发,则根本无法确定发送了多少字节。特别是在POSIX上,到目前为止发送的字节数仅存储在一旦引发异常就丢失的局部变量上;在Windows上,它只是做了一个重叠的WriteFile
并且除了成功的“写了所有内容”之外的任何事情都引发了异常。
我认为你至少关心这两个平台中的一个。 (如果没有,你可能不会编写跨平台代码,并且可以查看你关心的平台。)因此,没有直接的解决方案来解决你的问题。
如果你所描述的解决方法是可接受的,或者是另一个解决方法(比如一次只写一个字节 - 这可能效率更低,但可能更简单),那就这样做。
或者,您必须编辑您关心的write
实现(无论您是通过在运行时分配包和编辑fork,monkeypatching Serial.write
还是仅编写{{1}来执行此操作函数并在脚本中调用serial_write
而不是serial_write(port, data)
来提供所需的信息。
这看起来不太难。例如,在POSIX版本中,您只需要在port.write(data)
行之前的某处隐藏len(data)-t
。您可以将其粘贴在raise writeTimeoutError
对象的属性中,或将其作为额外参数传递给异常构造函数。 (当然,如果你正在尝试编写一个跨平台的程序,并且你并不能很好地了解所有平台以编写适当的实现,那么这不太可能是一个好的答案。)
实际上,考虑到实现你想要的并不难,你可能想在pyserial跟踪器上添加一个功能请求(理想情况下是一个补丁)。