質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

2回答

4980閲覧

Python バイナリデータのsocket通信で同じデータなのに送受信できるときとできないときがある

ngh_orange

総合スコア17

Socket.IO

Socket.IOはNode.js上で動くライブラリであり、すべてのブラウザとモバイルデバイスでリアルタイムのアプリを作動させる事を目的としています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

0クリップ

投稿2021/11/28 15:10

前提・実現したいこと

Pythonのソケット通信でファイルを送受信するソフトを作っています。
ファイルはpickleでバイナリデータにして送っています。

発生している問題・エラーメッセージ

同じファイル(バイナリデータ)なのに送受信が成功するときと失敗するときがあります
エラーメッセージは

pickle data was truncated

これになります。
送信側でのpickleデータをlenで数えたものと、受信側で最終的に受信できたデータの要素数を見ると
時々何故か途中までしか送信?受信?ができておらず、データが全然足りなくなってしまいます
この問題は、3回に一度ぐらいの確率でおき、コードを何も変えていないのにソフトを再起動すると治ることが多いです。

同じコード、同じデータでテストしているのに、なぜできるときとできないときがあるのかが本当に謎です
考えうる原因(例:Socketは不安定、そもそもそういう書き方は違うなど)があれば何でもいいので教えていただきたいです。

該当のソースコード

全文は長いので、受信側の受信部分のコードになります

Python

1rdata = sock.recv(4) 2datasize, = struct.unpack("l",rdata) 3rv = sock.recv(datasize) 4rv = pickle.loads(rv)

送信側は1、メインの送るバイナリデータ 2,1をlenで要素数を格納したデータ。の2つを送っています
1はpickleでバイナリ化したもので受信側のrvに入っていて、2はstructでpackしたデータになります

補足情報(FW/ツールのバージョンなど)

windows 10
VisualStudio Code
テストしたファイルタイプ txt pdf mp3 mp4
テストしたファイルサイズ 40バイトのものから~4MBぐらいのものまで、どれも成功するときとしないときがあります。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

例えば100バイトをsendしたとしても、recv(100)すると10バイトしか読まず、もう一度recvすると残りの90バイトを読むという事になるかもしれません。もしかすると2回でなく3回以上かかるかもしれません。ソケット通信というのはそういうものです。通信路の途中で、データの分割が発生する可能性があるからです。
なので、recvの返り値の長さを確認して、目的の長さが得られるまで繰り返します。

sendも同様で、100バイトsendしても40バイトしか送られないかもしれません。この場合はsendの返り値が40になるので、それを見て41バイト目から再度sendする必要があります。

投稿2021/11/28 17:23

otn

総合スコア85901

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ngh_orange

2021/11/29 07:43

回答ありがとうございます! recvの方なのですが、 rdata = sock.recv(4) datasize, = struct.unpack("l",rdata) while True:  rv = sock.recv(datasize)  if len(rv) > datasize:break rv = pickle.loads(rv) このように書けば期待する挙動ができますでしょうか? 自分の環境で試してみたのですが、たまに送れないorあまりにも受信?が長すぎる時がありまして...
otn

2021/11/29 10:53

全然駄目ですね。 分割して受信する訳なので、受信したものを毎回捨てては駄目です。 全部を順次継ぎ足していかないと。
ngh_orange

2021/11/30 07:32

返信ありがとうございます。 基本的にまだまだ勉強不足でした。色々工夫してやってみます!
guest

0

recv で読み取る場合は、期待するサイズデータを受信するまで、
独自にバッファに溜める必要があります。

送信側でも問題になる場合があり、send で送っている場合は、
データの欠損が出る可能性があるので sendall を使う。

Python Socket プログラミング HOW TO

send/recv の代わりに makefile で作成したfile-likeオブジェクトに対して
writer/read で、ファイルで読み書きするような期待する挙動になるはずです。

高水準のライブラリ socketserver や asyncio でも、
より扱いやすいストリーム形式での読み書き方法を提供してます。

投稿2021/11/28 15:40

teamikl

総合スコア8760

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ngh_orange

2021/11/29 07:44

回答ありがとうございます makefile、調べてみました。つまり、そもそもsend/recvは古い関数なのでしょうか? socket側がファイルを送るようなことを想定していて、それにあった関数を用意してくれているという認識であっていますでしょうか?
teamikl

2021/11/29 10:06 編集

古いからという訳ではなく、状況による使い分けで (意図の確認ですが、古くて廃止になった関数という訳ではありません。) socket は低水準なインターフェースなので、 read/write の内部で recv/send が使われているといった感じです。 例えば、recv/send は、ライブラリやフレームワーク内部で使われる事はあります。 アプリケーション等では、直接扱うことは少なく、大抵はより高水準な扱いやすい方法を用います。 追記: ファイルを送るなら sendfile メソッドもあります
ngh_orange

2021/11/30 07:33

返信ありがとうございます なるほど、大まかですが理解できました!わざわざ詳しくありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問