UDP通信を使うチャットプログラムを改変して、
小さいサイズの画像も送信できないかと、
画像を分割して送信するようにプログラムをつくったつもりですが、
画像データを受信できませんでした。
片方のパソコンからもう片方のパソコンに同じこのプログラムのtest.pyファイルを入れて、お互いIPアドレスを入力して通信する環境です。
テキストの通信はできています。
次のプログラムをどう修正すれば画像が遅れて受信できるようになりますでしょうか?
よろしくお願いします。
import tkinter as tk
from PIL import Image, ImageTk
import socket
import threading
from tkinter import filedialog
import base64
import io
# Port番号
PORTNUM = 8000
BUFFER_SIZE = 1024 # 画像データのバッファサイズ
class Application(tk.Frame):
def __init__(self, master=None):
super().__init__(master)
self.master.title("画像の表示") # ウィンドウタイトル
self.master.geometry("600x400") # ウィンドウサイズ(幅x高さ)
# Label for displaying received image
self.image_label = tk.Label(self.master)
self.image_label.place(x=280, y=160, width=160, height=120)
# Label for displaying image preview
self.preview_label = tk.Label(self.master)
self.preview_label.place(x=10, y=190, width=160, height=120)
# Button for selecting an image
self.select_img_button = tk.Button(self.master, text='画像を選択', command=self.select_image)
self.select_img_button.place(x=280, y=290, width=120, height=30)
# Button for sending an image
self.send_img_button = tk.Button(self.master, text='画像を送信', command=self.send_image)
self.send_img_button.place(x=10, y=290, width=120, height=30)
# UDP socket setup
self.sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
self.sock.bind(('', PORTNUM))
self.sock.settimeout(0.1)
# Entry widgets
self.ipaddr = tk.StringVar()
self.ipaddr.set('192.168.8.x')
ent1 = tk.Entry(self.master, textvariable=self.ipaddr)
ent1.place(x=120, y=20, width=120, height=20)
self.txdata = tk.StringVar()
self.txdata.set('send data')
ent2 = tk.Entry(self.master, textvariable=self.txdata)
ent2.place(x=10, y=100, width=260, height=20)
self.rxdata = tk.StringVar()
self.rxdata.set('receive data')
ent3 = tk.Entry(self.master, textvariable=self.rxdata)
ent3.place(x=10, y=160, width=260, height=20)
# Button for sending data
btn = tk.Button(self.master, text='送信', command=self.button_click)
btn.place(x=280, y=100, width=120, height=40)
# Start the timer thread
self.thread = threading.Thread(target=self.timerctrl)
self.thread.daemon = True
self.thread.start()
def resize_image(self, img_data, size=(160, 120)):
img = Image.open(io.BytesIO(img_data))
img = img.resize(size, Image.LANCZOS) # Use LANCZOS resampling filter
img = ImageTk.PhotoImage(img)
return img
# タイマー処理(約1秒周期)
def timerctrl(self):
try:
# UDP受信
recvdata, fromdata = self.sock.recvfrom(BUFFER_SIZE)
# 受信データを変換
recvtext = recvdata.decode('utf-8')
except socket.timeout: # 受信タイムアウト
recvtext = ''
# データを受信した場合
if recvtext.startswith("IMG:"):
# 受信データが画像データである場合
img_data = base64.b64decode(recvtext[4:])
img = self.resize_image(img_data)
self.image_label.config(image=img)
self.image_label.image = img
elif recvtext: # 画像データでなく、かつデータが存在する場合
self.rxdata.set(recvtext)
# タイマーを再設定
self.master.after(1000, self.timerctrl)
No.1ベストアンサー
- 回答日時:
Pythonはいまいち理解度がアレですが…
UDPパケットの場合、もろもろの送達保証はなかったはずです。
https://ja.wikipedia.org/wiki/User_Datagram_Prot …
送信側は複数回(?)で送信しているようですが、受信側はそれを正しく再構築できているんでしょうか?
複数回のどれか一つでも欠落した場合に再送処理なんてものはしてくれませんし、そもそも受信する順番自体が保証されません。
1/2/3/4/5/6…という順番で送信しても、受信側で2/6/4/2/1…のように受信される可能性もあるわけですが、そこらへんは大丈夫ですか?
(同じパケットが複数届く(通った経路が違う)ということもある…とされています)
# ローカルネットワークとか、LANケーブル直結とかならそうそうパケット欠落やら順番が入れ替わることはないかもしれませんけど。
チャット程度であればたいしたサイズのパケットにはならないでしょうから順番が入れ替わるということは考慮しなくても大丈夫かもしれませんが、
バイナリデータで欠落があった場合にどうなるか…とかも考慮が必要でしょう。
UDPヘッダ的には1パケットで約64k程度は送れる…ようですが、下位レイヤーで分割されたパケットが正しく復元されるのかはちょっと不明ですね。
# 判定用のチェックサムがあるので、チェックサム異常となれば、UDPパケット自体が破棄されておしまいでしょう。(破棄されたこと自体の通知もない…んじゃないでしょうかねぇ)
ということで、UDPでやるならばそういうパケットロスやら順番やら再送やらのプロトコルは自前で処理する必要があるかと。
いやなら素直にTCPでやりとり…でしょうね。
多対多になるチャットの場合にTCPで…というのは厳しいかもしれませんげと。
あと…本筋ではありませんが、バイナリデータをBASE64で送る場合は元データより最終的なサイズが増えますので注意しましょう。
https://ja.wikipedia.org/wiki/Base64#%E5%95%8F%E …
UDPでやるならばパケットロスやらデータ送信順番やら再送やらのプロトコルは自前で処理する必要があるんですね。もう一度一から考え直します。ありがとうございました。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- HTML・CSS CSSが効かずどのように指定すれば良いか分からないのでアドバイスお願い致します 2 2023/06/07 12:25
- JavaScript アップロードファイルの種類によって処理を分岐させたいのですが書き方が分からずアドバイスお願いします 4 2023/06/17 19:12
- その他(プログラミング・Web制作) Pythonで会員サイトの自動ログイン ID Nameがない 1 2022/12/16 02:09
- JavaScript clear機能を失わずにファイルアップロード機能を作成したい 3 2023/06/10 16:12
- その他(プログラミング・Web制作) pythonのグローバル変数 2 2022/11/25 18:02
- その他(プログラミング・Web制作) pythonをjupiter notebookからmecabで頻出の高い単語の抽出について(Runt 1 2022/12/17 18:08
- その他(プログラミング・Web制作) pythonで、tkinterとpillowの組み合わせ 2 2022/08/16 17:42
- その他(プログラミング・Web制作) pythonのプログラムについての質問です。 1 2023/05/26 10:31
- HTML・CSS 【HTML】【CSS】【Swiper】 元の画像は横1200×縦600なのですが、実際のサイト上に反 5 2022/07/16 13:57
- Ruby パイソンのクラスについて 3 2023/06/20 07:30
関連するカテゴリからQ&Aを探す
おすすめ情報
- ・「みんな教えて! 選手権!!」開催のお知らせ
- ・漫画をレンタルでお得に読める!
- ・【選手権お題その2】この漫画の2コマ目を考えてください
- ・2024年に成し遂げたこと
- ・3分あったら何をしますか?
- ・何歳が一番楽しかった?
- ・治せない「クセ」を教えてください
- ・【大喜利】看板の文字を埋めてください
- ・【大喜利】【投稿~12/17】 ありそうだけど絶対に無いことわざ
- ・【選手権お題その1】これってもしかして自分だけかもしれないな…と思うあるあるを教えてください
- ・【穴埋めお題】恐竜の新説
- ・我がまちの「給食」自慢を聞かせてっ!
- ・冬の健康法を教えて!
- ・一番好きな「クリスマスソング」は?
- ・集合写真、どこに映る?
- ・自分の通っていた小学校のあるある
- ・フォントについて教えてください!
- ・これが怖いの自分だけ?というものありますか?
- ・スマホに会話を聞かれているな!?と思ったことありますか?
- ・それもChatGPT!?と驚いた使用方法を教えてください
- ・見学に行くとしたら【天国】と【地獄】どっち?
- ・これまでで一番「情けなかったとき」はいつですか?
- ・この人頭いいなと思ったエピソード
- ・あなたの「必」の書き順を教えてください
- ・10代と話して驚いたこと
- ・14歳の自分に衝撃の事実を告げてください
- ・人生最悪の忘れ物
- ・あなたの習慣について教えてください!!
- ・都道府県穴埋めゲーム
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
favicon.ico はもういらない?
-
inputタグでサーバにデータを送...
-
レスポンシブ対応のHTML・CSS(...
-
画像の場合のみ、下線を消す方...
-
ボタンをセル内一杯に表示させ...
-
XSL変換したが画像が表示できま...
-
footerの背景が切れて、背景画...
-
リンクを知らせる手のマークが...
-
画像をクリックして元に戻すには
-
リンクを選択したときの青い枠...
-
プルダウンの選択リストの中に...
-
HTMLでボタンを横に2つ並べる方法
-
画像をクリックして同じページ...
-
cssヘッダー画像の下に配置した...
-
【HTML/CSS】ボタンの枠が伸び...
-
1箇所に複数画像を別々に配置は...
-
UDP通信を使うチャットプログラ...
-
htmlの文字が縦書きになる
-
画像イメージの上下左右、欲し...
-
複数のボタンを等間隔に、かつ...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
リンクを知らせる手のマークが...
-
ボタンをセル内一杯に表示させ...
-
XML画像データををHTMLで簡単に...
-
画像の場合のみ、下線を消す方...
-
favicon.ico はもういらない?
-
レスポンシブ対応のHTML・CSS(...
-
3つの画像を中央に寄せて表示さ...
-
アップロードするとレイアウト...
-
HTMLのIMAGEに。。
-
table で画像をピッタリとくっ...
-
画像をリンクさせると紫の枠が...
-
cssで、チェックボックスの画像...
-
【HTML/CSS】ボタンの枠が伸び...
-
クリッカブルマップがきかない!?
-
UDP通信を使うチャットプログラ...
-
画像を、横並びにするには!?
-
DIVタグについて
-
1箇所に複数画像を別々に配置は...
-
画像をクリックして元に戻すには
-
リンクを選択したときの青い枠...
おすすめ情報
# 画像を選択する関数
def select_image(self):
img_path = filedialog.askopenfilename()
with open(img_path, "rb") as img_file:
img_data = base64.b64encode(img_file.read()).decode('ascii')
selected_img = self.resize_image(base64.b64decode(img_data))
self.preview_label.config(image=selected_img)
self.preview_label.image = selected_img
# 画像データを送信
self.sock.sendto(bytes("IMG:" + img_data, 'utf-8'), (self.ipaddr.get(), PORTNUM))
# 画像を送信する関数
def send_image(self):
img_path = filedialog.askopenfilename()
with open(img_path, "rb") as img_file:
img_data = base64.b64encode(img_file.read()).decode('ascii')
# 画像データを分割して送信
chunk_size = 800 # データを分割するサイズ
img_data_bytes = bytes("IMG:" + img_data, 'utf-8')
for i in range(0, len(img_data_bytes), chunk_size):
chunk = img_data_bytes[i:i+chunk_size]
self.sock.sendto(chunk, (self.ipaddr.get(), PORTNUM))
# 画像データを分割して送信
chunk_size = 800 # データを分割するサイズ
img_data_bytes = bytes("IMG:" + img_data, 'utf-8')
for i in range(0, len(img_data_bytes), chunk_size):
chunk = img_data_bytes[i:i+chunk_size]
self.sock.sendto(chunk, (self.ipaddr.get(), PORTNUM))
# ボタンが押されたときに実行する関数
def button_click(self):
addr = self.ipaddr.get() # 送信先IPアドレスを格納する
data = self.txdata.get() # 送信データを格納する
# UDP送信
self.sock.sendto(bytes(data, 'utf-8'), (addr, PORTNUM))
if __name__ == "__main__":
root = tk.Tk()
app = Application(master=root)
app.mainloop()
(誤)どう修正すれば画像が遅れて受信できるようになります
→(正)どう修正すれば画像が送信できて受信できるようになります