簡體   English   中英

如果客戶端與服務器斷開連接,如何斷開連接?

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

我已經編寫了一個服務器和一個客戶端,如果我關閉客戶端並再次連接,我在服務器上的客戶端列表就會堆積起來。 第一次斷開連接時,我會打印出列表中的內容,因此首先得到以下信息:

{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)>

我第二次連接它只是堆疊起來,所以看起來像這樣:

{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)>}

我該如何做才能使它斷開連接? 這是服務器代碼:

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()

這是客戶端代碼:

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()

客戶端代碼只是我擁有的GUI客戶端代碼的cli版本(因為它寫的太久了,所以不再寫),但是它是相同的代碼。 在GUI版本上,我有一個斷開按鈕, 如下所示:

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

我在這里做錯了什么?

clients字典僅添加到,從未刪除。 像下面這樣的東西應該起作用。 捕獲任何異常並退出以從字典中刪除密鑰。

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)

順便說一句,由於需要start() not start ,下面的代碼從不啟動線程。 偵聽器啟動是因為在target=listener()調用了該target=listener() ,該target=listener應為target=listener

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

但是不需要啟動線程來調用偵聽器。 只需使用:

if __name__ == '__main__':
    listener()

您最終還會遇到消息問題。 TCP是一種流協議,因此您不能假定每個recv都能接收到send send不能保證將發送每個字節...檢查返回值或使用sendall 緩慢發送的小消息可能永遠不會顯示問題,但發送充滿多字節UTF-8編碼字符的大消息,則會出現錯誤。 請參閱我的最新答案,以簡單的方式解決它。

暫無
暫無

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

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