iT邦幫忙

0

Python Socket UDP廣播 Error (Tkinter)

打算為基於廣播的UDP聊天室做一個UI介面,並且可以隨時切換埠來做到切換頻道的效果,但在接收封包的部分遇到了問題。

VScode報錯:

in recv
recv_socket.bind(('', port))
OSError: [WinError 10022] 提供了一個不正確的引數。

程式碼:

import tkinter as tk
from socket import socket, AF_INET, SOCK_DGRAM, SOL_SOCKET, SO_REUSEADDR, SO_BROADCAST
from time import sleep
from threading import Thread

#發送封包
def send(event=None):
    entry = send_entry.get()
    send_entry.delete(0, "end")
    port = int(channel_entry.get())
    sendSocket = socket(AF_INET, SOCK_DGRAM)
    sendSocket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
    sendSocket.sendto(entry.encode("utf-8"), ('255.255.255.255', port))

#接收器
recv_socket = socket(AF_INET, SOCK_DGRAM)
recv_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
recv_socket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
def recv():
    text_box.config(state=tk.NORMAL)
    text_box.insert(tk.END, "[*] 載入 UDP 訊息接收器完成\n")
    text_box.config(state=tk.DISABLED)
    while True:
        port = int(channel_entry.get())
        recv_socket.bind(('', port))
        try:
            recv_data = recv_socket.recvfrom(1024)
            text_box.config(state=tk.NORMAL)
            text_box.insert(tk.END, f"{recv_data[1][0]}:{recv_data[0].decode('utf-8')}\n")
            text_box.config(state=tk.DISABLED)
            text_box.see(tk.END)
            sleep(1)
        except OSError:
            text_box.config(state=tk.NORMAL)
            text_box.insert(tk.END, "[*] 超過單次字數限制\n")
            text_box.config(state=tk.DISABLED)
            text_box.see(tk.END)

#接收器線呈
Thread(target=recv, daemon=True).start()

app.mainloop()

1 個回答

1
JackKuo
iT邦新手 4 級 ‧ 2020-11-16 10:56:49
最佳解答

那個錯誤是說你重複 bind 了這個 socket。
bind() 只需要做一次,不該放在 while 內:

#接收器
recv_socket = socket(AF_INET, SOCK_DGRAM)
recv_socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
recv_socket.setsockopt(SOL_SOCKET, SO_BROADCAST, 1)
recv_socket.bind(('', port))
def recv():
    text_box.config(state=tk.NORMAL)
    text_box.insert(tk.END, "[*] 載入 UDP 訊息接收器完成\n")
    text_box.config(state=tk.DISABLED)
    while True:
        port = int(channel_entry.get())
        try:
.
.
.
看更多先前的回應...收起先前的回應...

謝謝你,原本我也這樣寫,是後來我將它移進去的。但是我想做到切換的功能,在recvfrom之前不是得先bind嗎?目前打算使用Tkinter的after來callback線呈,而recv的壽命改成有限的。但不知為何一直沒有效果QQ

JackKuo iT邦新手 4 級 ‧ 2020-11-17 10:30:17 檢舉

不太懂你要的功能,我對 Tkinter 也不熟。但我猜你要的方式可以透過依賴注入的方式達成,或是把 socket 當作全域變數來傳入,這兩種都是在 function 外面就建好 socket。
總之只能 bind 一次,要不就重建一個 socket,只是這樣開銷有點高。

長這樣:

頻道可以輸入。所以你的意思是說就算用異步監聽更換頻道事件,也無法達成多次bind的功能囉?

JackKuo iT邦新手 4 級 ‧ 2020-11-18 11:35:46 檢舉

一個 socket 就只能 bind 一次,除非再次開新的 socket ?

是的,只是這樣好像有點浪費資源,而且又不安全。

我要發表回答

立即登入回答