簡體   English   中英

套接字未關閉/關閉(python3)

[英]Socket not shutting down/closing (python3)

我有一個server變量,它是套接字 object。
出於某種原因,當我執行server.shutdown(socket.SHUT_RDWR)時,它給了我以下錯誤:

OSError: [WinError 10057] A request to send or receive data was disallowed because the socket is not connected and (when sending on a datagram socket using a sendto call) no address was supplied

我嘗試使用.close() ,但它給了我這個:

OSError: [WinError 10038] an operation was attempted on something that is not a socket

服務器代碼:

import sys
import time
import socket
import threading
import tkinter as tk
from tkinter import messagebox as msgbox

HEADER = 64
PORT = 5050
SERVER = socket.gethostbyname(socket.gethostname())
ADDR = (SERVER, PORT)
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "%client_disconnect"

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(ADDR)
server_active = True

messages = []

def add_message(message):
    local_t = time.localtime()
    sent_at = time.strftime("%Y.%m.%d %H:%M:%S", local_t)
    messages.append(f"{sent_at} | {str(message)}")

def handle_client(conn, addr):
    print(f"\n===[DEBUG (SERVER)]\tHandling connection: {addr}")

    connected = True
    while connected:
        msg_len = conn.recv(HEADER).decode(FORMAT)
        if msg_len:
            msg_len = int(msg_len)
            msg = conn.recv(msg_len).decode(FORMAT)
            print(f"\n===[DEBUG ({addr})]\tMessage length: {msg_len}; Message: {msg}")

            if msg == DISCONNECT_MESSAGE:
                connected = False

        if not server_active:
            connected = False

    conn.close()

def start():
    server.listen()
    print(f"\n===[DEBUG (SERVER)]\tListening on {SERVER}")
    while True:
        print("\n===[DEBUG (SERVER)]\tWaiting for client connection")
        conn, addr = server.accept()
        thread = threading.Thread(target=handle_client, args=(conn, addr))
        thread.start()
        print(f"\n===[DEBUG (SERVER)]\tNew connection: ({addr}); "
              f"Current active connections: {threading.active_count() - 1}")

def on_closing():
    global server_active
    if msgbox.askokcancel("Serverside", "Are you sure you want to quit? This will fully shut down the server"
                                        "and disconnect all clients."):
        server_active = False
        window.destroy()
        server.close()

# window is empty
window = tk.Tk()
window.wm_geometry("700x500")
window.title("Serverside")
window.protocol("WM_DELETE_WINDOW", on_closing)

t = time.localtime()
start_time = time.strftime("%Y.%m.%d %H:%M:%S", t)

print("===[DEBUG (SERVER)]\tStarting Server")
server_thread = threading.Thread(target=start)
server_thread.start()
add_message(f"Server started at: {start_time}")

tk.mainloop()

客戶端代碼:

import socket
import threading
import tkinter as tk
from tkinter import messagebox as msgbox

HEADER = 64
PORT = 5050
FORMAT = 'utf-8'
DISCONNECT_MESSAGE = "%client_disconnect"
SERVER = None
ADDR = None

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

def send(msg):
    message = msg.encode(FORMAT)
    msg_len = len(message)
    send_len = str(msg_len).encode(FORMAT)
    send_len += b' ' * (HEADER - len(send_len))
    client.send(send_len)
    client.send(message)

def connect_to(server):
    global SERVER, ADDR
    SERVER = server
    ADDR = (SERVER, PORT)
    client.connect(ADDR)

def on_closing():
    if msgbox.askokcancel("Client", "Are you sure you want to quit? You will be disconnected from the server."):
        send(DISCONNECT_MESSAGE)
        window.destroy()

def handle_messages():
    msg = str(entry.get())
    send(msg)

    if msg == DISCONNECT_MESSAGE:
        window.destroy()

connect_to(socket.gethostbyname(socket.gethostname()))

window = tk.Tk()
window.geometry("600x450")
window.title("Client")
window.protocol("WM_DELETE_WINDOW", on_closing)

entry = tk.Entry()
entry.place(x=0, y=0, width=100, height=30)

button = tk.Button(command=handle_messages)
button.place(x=0, y=50, width=50, height=20)

tk.mainloop()

也許我錯誤地關閉了服務器?

所以這個錯誤有點奇怪。 您正在正確關閉套接字,但沒有正確處理線程。

發生的事情是您的start thread接受新連接,但您正在關閉主線程上的套接字。 所以發生的事情是主線程關閉套接字,但start thread仍在接受連接,但由於套接字已關閉,它會拋出該錯誤。 這個錯誤沒什么大不了的,你可以忽略它,如果你想要或者包裹在一個 catch 中,然后跳出 while 循環,或者你可以在關閉套接字之前加入你的線程,然后就沒有更多的錯誤了。

需要注意兩點:

  1. try catch 可能是更簡單和更優雅的選擇,但請注意不要捕獲錯誤並丟棄它。 可能會使其他錯誤難以發現
  2. 您需要將線程設置為守護進程,這意味着程序在退出前不會等待它們加入。

這是修改后的代碼,以避免使用超時的錯誤。

def start():
    server.listen()
    print(f"\n===[DEBUG (SERVER)]\tListening on {SERVER}")
    while True:
        print("\n===[DEBUG (SERVER)]\tWaiting for client connection")
        conn, addr = server.accept()
        thread = threading.Thread(target=handle_client, args=(conn, addr), daemon=True) # This is a daemon thread now
        thread.start()
        print(f"\n===[DEBUG (SERVER)]\tNew connection: ({addr}); "
              f"Current active connections: {threading.active_count() - 1}")

...

def on_closing():
    global server_active
    if msgbox.askokcancel("Serverside", "Are you sure you want to quit? This will fully shut down the server"
                                        "and disconnect all clients."):
        server_active = False
        window.destroy()
        server_thread.join(timeout=0.0) # Timeout the thread to force it to join
        server.close()

...

server_thread = threading.Thread(target=start, daemon=True) # I'm a daemon thread so i dont block the program from closing
server_thread.start()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM