简体   繁体   English

如果客户端与服务器断开连接,如何断开连接?

[英]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. 客户端代码只是我拥有的GUI客户端代码的cli版本(因为它写的太久了,所以不再写),但是它是相同的代码。 On the GUI version I have a disconnect button that looks like this: 在GUI版本上,我有一个断开按钮, 如下所示:

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

What am I doing wrong here? 我在这里做错了什么?

The clients dictionary is only added to, never removed. clients字典仅添加到,从未删除。 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 . 顺便说一句,由于需要start() not start ,下面的代码从不启动线程。 The listener starts because it is called in target=listener() , which should be target=listener : 侦听器启动是因为在target=listener()调用了该target=listener() ,该target=listener应为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. TCP是一种流协议,因此您不能假定每个recv都能接收到send send doesn't guarantee it will send every byte either...check the return value or use sendall . send不能保证将发送每个字节...检查返回值或使用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. 缓慢发送的小消息可能永远不会显示问题,但发送充满多字节UTF-8编码字符的大消息,则会出现错误。 See this recent answer of mine for a simple way to solve it. 请参阅我的最新答案,以简单的方式解决它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在从pb.Root继承的服务器中检测丢失的客户端连接? - How do I detect a lost client connection in a server that inherits from pb.Root? 当客户端与服务器断开连接时,我可以从“try:”块中的 function 内部引发异常吗? - can i raise exception from inside a function in the 'try:' block when client disconnects from the server? Django:客户端从流断开连接后清理redis连接 - Django: Cleaning up redis connection after client disconnects from stream 如何使PySolr断开连接? - How do I make PySolr drop a connection? 如何在LabVIEW服务器和Python客户端之间建立TCP连接,将来自Python的(数据)角度传输到LabVIEW? - How do I make a TCP connection between LabVIEW server and Python client where (data) angles from Python are to be transferred to LabVIEW? 当客户端断开连接时,如何在django中停止StreamingHttpResponse? - How do you stop a StreamingHttpResponse in django when the client disconnects? 当另一个客户端连接到服务器时客户端断开连接 - Client disconnects when another client connects to the server 每当特定应用程序尝试使用互联网连接时,mitmproxy 客户端和服务器就会断开连接 - mitmproxy Client and Server disconnects whenever a specific app tries to use internet connection 如何检测客户端何时断开与UDS的连接(Unix域套接字) - How to detect when a client disconnects from a UDS (Unix Domain Socket) 如何从远程连接访问python http服务器? - How do I access a python http server from a remote connection?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM