简体   繁体   中英

How do I drop a connection if client disconnects from server?

I have written a server and a client and if I close my client and connect again my clients list on the server just stacks up. First time I disconnect I print out whats on the list so first I get this:

{612: <socket.socket fd=612, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.77', 22050), raddr=('192.168.1.77', 53531)>

Second time I connect it just stacks up so it looks like this:

{612: <socket.socket fd=612, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.77', 22050), raddr=('192.168.1.77', 53531)>, 620: <socket.socket fd=620, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=0, laddr=('192.168.1.77', 22050), raddr=('192.168.1.77', 53532)>}

How do I make it so it just drops the connection? Here is the server code:

import socket
import threading
from _thread import *
from threading import Thread

clients = {}

def message(c):
    while True:
        try:
            data = c.recv(1024).decode("utf-8")
            print("Recieved from: " + str(data))
            if not data:
                print("Client Disconnected.")
                print(clients)
                break

            # skicka meddelanden till client
            for client in clients.values():
                try:
                    if client == c:
                        continue
                    client.sendall(data.encode("utf-8"))
                except ConnectionAbortedError:
                    print("[!] Connection aborted ")
                    print(str(clients))
                except ConnectionResetError:
                    print("[!] Connection reset error ")
                    print(str(clients))
        except ConnectionResetError:
            print("[!] - An existing connection was forcibly closed by the remote host. \n")
            break

def listener():
    host = "192.168.1.77"
    port = 22050
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    s.bind((host, port))
    s.listen(5)
    print("\nServer has started.\n\n" + "Host: " + host + "\nPort: " + str(port))
    print("______________________________________________________________________\n")
    while True:
        c, addr = s.accept()
        print(str(addr) + " has connected.")
        clients[c.fileno()] = c
        threading.Thread(target=message, args=(c,)).start()


if __name__ == '__main__':
    listenerthread = Thread(target=listener())
    listenerthread.start
    #listener()

And here is the client code:

import socket
import os
from multiprocessing import Process
from threading import Thread
import sys

print("... Awaiting connection from server ...")

host = "192.168.1.77"
port = 22050

try:
    s = socket.socket()
    s.connect((host, port))
except ConnectionRefusedError:
    print("Server is down.")
    sys.exit()
try:
    print("Connected!")

    def send():
        while True:
           message = input("-> ")
           s.send(message.encode("utf-8"))
           #recieve = s.recv(1024).decode("utf-8")
           #print("- Server: " + recieve)

    def recv():
        recieve = s.recv(1024).decode("utf-8")
        print("\n" + "Server: " + recieve)

#    while message !="quitclient":
#        s.send(message.encode("utf-8"))
#        recieve = s.recv(1024).decode("utf-8")
#        print("Recieved from server: " + recieve)
#        message = input("-> ")
#    s.close()

except ConnectionResetError:
    print("Disconnected!")
    input("Press enter to exit...")
    quit()
sendthread = Thread(target=send)
recvthread = Thread(target=recv)

sendthread.start()
recvthread.start()

The client code is just a cli version of the GUI client code I have (not writing it since its way too long) but its the same code. On the GUI version I have a disconnect button that looks like this:

def Disconnect():
    s.shutdown(socket.SHUT_RDWR)
    s.close()

What am I doing wrong here?

The clients dictionary is only added to, never removed. Something like the following should work. Catch any exception and drop out to remove the key from the dictionary.

def message(c):
    try:
        while True:
            data = c.recv(1024).decode("utf-8")
            print("Received from: " + str(data))
            if not data:
                print("Client Disconnected.")
                print(clients)
                break

            # skicka meddelanden till client
            for client in clients.values():
                if client == c:
                    continue
                client.sendall(data.encode("utf-8"))
    except Exception as e:
        print(e)
    clients.pop(c.fileno())
    print(clients)

As an aside, the code below never starts a thread due to needing start() not start . The listener starts because it is called in target=listener() , which should be target=listener :

if __name__ == '__main__':
    listenerthread = Thread(target=listener())
    listenerthread.start
    #listener()

But starting a thread to call listener is not needed. Just use:

if __name__ == '__main__':
    listener()

You'll also eventually have a problem with messages. TCP is a streaming protocol, so you can't assume each recv receive exactly what send sent. send doesn't guarantee it will send every byte either...check the return value or use sendall . Small messages sent slowly may never show the problem, but send large messages full of multi-byte UTF-8-encoded characters and you'll get an error. See this recent answer of mine for a simple way to solve it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM