I have a server
variable which is socket object.
For some reason, when I do server.shutdown(socket.SHUT_RDWR)
it gives me following error:
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
I tried using .close()
, but it gave me this:
OSError: [WinError 10038] an operation was attempted on something that is not a socket
Server code:
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()
Client code:
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()
Maybe I am shutting down server incorrectly?
CodePudding user response:
So the error is kind of a weird one. You are shutting down the socket properly but you're not handling your threads appropriately.
What is happening is you have your start thread
accepting new connections but you're closing the socket on the main thread. So what happens is the main thread closes the socket but the start thread
is still accepting connections but since the socket was closed it throws that error. This error is no big deal you could just ignore it if you want or wrap in a catch and just break out of the while loop or you could join your thread before shutting down the socket and then no more error.
Two things to note:
- A try catch would prob be the easier and more graceful option but be care not to catch a error and just discard it. Could make other bugs hard to find
- You need to set the threads to be daemons which means that the program will not wait for them to join before exiting.
Heres the modified code to avoid the error using timeout.
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()