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

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

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

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

Python

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

Q&A

解決済

2回答

2463閲覧

pythonのsocket通信でのUnpicklingErrorについて

succulent

総合スコア12

Socket.IO

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

Python

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

0グッド

0クリップ

投稿2020/11/10 09:20

前提・実現したいこと

python3.8によるsocketを使ったserver-client通信をしようとしています.
具体的にはコネクションを張ったのち,以下のような流れで動作します.

  1. send.pyが送信データサイズと送信データを送信
  2. recv.pyが送信データサイズを受信し,サイズ分もう一度受信
  3. recv.pyが送信データをコピーして送信
  4. send.pyで送信データを受信して表示

その際,UnpicklingErrorが発生しプログラムが途中で終了してしまいます.

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

Traceback (most recent call last): File "recv.py", line 25, in <module> d = pickle.loads(full_data) _pickle.UnpicklingError: unpickling stack underflow

該当のソースコード

python

1####send.py#### 2import sys 3import socket 4import pickle 5 6BUF_SIZE = 1024 7 8send_msg = [1,2,3,4] 9msg_len = sys.getsizeof(send_msg) 10 11with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 12 s.connect(('127.0.0.1', 50001)) 13 14 msg = pickle.dumps(msg_len) 15 s.send(msg) 16 msg = pickle.dumps(send_msg) 17 s.send(msg) 18 print("send msg") 19 20 full_msg = b'' 21 while True: 22 msg = s.recv(BUF_SIZE) 23 full_msg += msg 24 if len(msg) < BUF_SIZE: 25 break 26 print(pickle.loads(full_msg))

python

1####recv.py#### 2import socket 3import select 4import pickle 5 6with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 7 s.bind(('127.0.0.1', 50001)) 8 s.listen(1) 9 10clientsock, address = s.accept() 11 12 full_data = b'' 13 msg_len = clientsock.recv(28) # size of int 14 msg_len = pickle.loads(msg_len) 15 print(type(msg_len)) 16 print(msg_len) 17 18 while msg_len > 0: 19 data = clientsock.recv(1024) 20 print(data) 21 full_data += data 22 msg_len -= 1024 23 if msg_len <= 0: break 24 25 print(type(full_data)) 26 print(full_data) 27 d = pickle.loads(full_data) 28 print(d) 29 clientsock.send(pickle.dumps(d))

試したこと

数回に一度送受信が正常終了しましたが,ほとんどエラーが発生しました.

何か疑問点があればお聞きください.
よろしくお願い致しします.

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

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

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

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

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

guest

回答2

0

解決済みではございますが、ほんの少しだけ丁寧な送受信にしてみました。

python

1####send.py#### 2# Data Format 3# +---------------+--------------------------------+ 4# | length(4byte) | send_msg(length byte) | 5# +---------------+--------------------------------+ 6 7import sys 8import socket 9import pickle 10 11BUF_SIZE = 1024 12 13send_msg = [1,2,3,4] 14msg_len = sys.getsizeof(send_msg) 15 16with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 17 s.connect(('127.0.0.1', 50001)) 18 19 value = pickle.dumps(send_msg) 20 length = len(value) 21 22 s.send(length.to_bytes(4, "big")) 23 s.send(value) 24 print("send msg") 25 26 full_msg = b'' 27 while True: 28 msg = s.recv(BUF_SIZE) 29 full_msg += msg 30 if len(msg) < BUF_SIZE: 31 break 32 print(pickle.loads(full_msg)) 33

python

1####recv.py#### 2import socket 3import select 4import pickle 5 6with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 7 8 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 9 10 s.bind(('127.0.0.1', 50001)) 11 s.listen(1000) 12 13 14 clientsock, address = s.accept() 15 16 full_data = b'' 17 msg_len = clientsock.recv(4) 18 print(type(msg_len)) 19 print(msg_len) 20 21 msg_len = int.from_bytes(msg_len, "big") 22 print(msg_len) 23 24 while msg_len > 0: 25 data = clientsock.recv(1024) 26 print(data) 27 full_data += data 28 msg_len -= 1024 29 if msg_len <= 0: break 30 31 print(type(full_data)) 32 print(full_data) 33 d = pickle.loads(full_data) 34 print(d) 35 clientsock.send(pickle.dumps(d))

console

1$ python3 recv.py 2<class 'bytes'> 3b'\x00\x00\x00\x10' 416 5b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04e.' 6<class 'bytes'> 7b'\x80\x03]q\x00(K\x01K\x02K\x03K\x04e.' 8[1, 2, 3, 4] 9 10$ python3 send.py 11send msg 12[1, 2, 3, 4] 13

投稿2020/11/11 12:32

sukekeke0

総合スコア331

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

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

succulent

2020/11/11 13:09

わざわざありがとうございます!! 恥ずかしながらpythonでのパケットフォーマット定義に手間取っていたので,とても助かりました,, ご丁寧にありがとうございましたm(__)m
guest

0

ベストアンサー

pickleで変換する意図が良く分からなかったので、下記のようにpickleの処理を削ってみました。
これではダメでしょうか?

python

1####send.py#### 2import sys 3import socket 4 5BUF_SIZE = 1024 6 7send_msg = [1,2,3,4] 8msg_len = sys.getsizeof(send_msg) 9 10with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 11 s.connect(('127.0.0.1', 50001)) 12 13 s.send(str(msg_len).encode()) 14 s.send(str(send_msg).encode()) 15 print("send msg") 16 17 full_msg = b'' 18 while True: 19 msg = s.recv(BUF_SIZE) 20 full_msg += msg 21 if len(msg) < BUF_SIZE: 22 break 23 print(full_msg)

python

1####recv.py#### 2import socket 3import select 4 5with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: 6 7 s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 8 9 s.bind(('127.0.0.1', 50001)) 10 s.listen(1000) 11 12 13 clientsock, address = s.accept() 14 15 full_data = b'' 16 msg_len = clientsock.recv(2) # size of int 17 print(type(msg_len)) 18 print(msg_len) 19 20 rs = int(msg_len.decode()) 21 22 while rs > 0: 23 data = clientsock.recv(1024) 24 print(data) 25 full_data += data 26 rs -= 1024 27 if rs <= 0: break 28 29 print(type(full_data)) 30 print(full_data) 31 clientsock.send(full_data)

実行結果

console

1$ python3 recv.py 2<class 'bytes'> 3b'96' 4b'[1, 2, 3, 4]' 5<class 'bytes'> 6b'[1, 2, 3, 4]' 7 8$ python3 send.py 9send msg 10b'[1, 2, 3, 4]'

投稿2020/11/10 13:59

編集2020/11/10 14:00
sukekeke0

総合スコア331

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

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

succulent

2020/11/10 15:39

送受信は問題なく動作しました,回答ありがとうございます! 出来れば最終的にsend.pyでリストとして扱える形にしたいのですが,decode後にstr->listできるような関数はあるでしょうか?(情報不足すみません)
sukekeke0

2020/11/11 03:47 編集

あぁ、pythonで扱えるデータをclient/server間でピンポンしたかったわけですね。 なのでpickleを使うというわけですね。 単にピンポンさえ出来れば良いのかと思い、テキトーな回答をしてしまいました。後ほど修正します。
succulent

2020/11/11 04:53

いえいえ!reprで復元することが出来ました. こちらの方が扱いが簡単でしたので,ベストアンサーにさせていただきますm(__)m
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.46%

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

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

質問する

関連した質問