TCP/IP 接続を介して対話する 2 つのアプリケーションがあります。シリアル接続でもやり取りできるようにする必要があります。
ソケット IO とシリアル IO の間にはいくつかの違いがあり、移植が思ったほど簡単ではありません。
違いの 1 つは、送信/書き込みタイムアウトのセマンティクスと、接続で正常に渡されたデータの量についてアプリケーションが行う可能性のある仮定に関するものです。この量を知ることで、アプリケーションは後で送信する必要がある残りのデータも認識します。
Socket.send
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 を予期せず取得します。何か不足していますか?
その行動が典型的かどうかはわかりません。それが問題になる場合は、ヌルモデム ケーブルを介して接続された 2 つの USB-to-COM アダプターを使用して、Windows 7 64 ビットで PySerial を試します。Tera Term の 2 つのインスタンスが相互に通信できるため、このセットアップは機能しているようです。
接続を中止してユーザーに問題を通知する以外の方法でシリアル書き込みタイムアウトを処理しているかどうかを知っておくと役に立ちます。
現在、タイムアウトが発生する前に書き込まれたデータの量がわからないため、ノンブロッキング書き込みを使用し、ソケットのようなタイムアウト セマンティクスをそのレベルより上に維持する回避策を考えています。これが非常に効率的なソリューションになるとは思いません (:-)) が、幸いにも、私のアプリケーションは比較的まれで短いメッセージを交換するので、パフォーマンスは許容範囲内にあるはずです。
[編集]
ノンブロッキング シリアル書き込みの詳細
ノンブロッキング書き込みがどのように機能するかを理解しているかどうかを確認するために、簡単なプログラムを作成しました。
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 バイト: 'Hello! こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!'
0 バイトのメッセージが書き込まれました: ''
70 バイトのメッセージ
を受信しています 70 バイトのメッセージが受信されました: 'Hello! こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!こんにちは!'
私は非常に混乱しています。送信者はデータが送信されていないと考えていますが、受信者はすべてを取得しています。ここで非常に基本的な何かが欠けているに違いありません...
コメント/提案/質問は大歓迎です!