我的服务器如何知道客户端已断开连接?

Posted

技术标签:

【中文标题】我的服务器如何知道客户端已断开连接?【英文标题】:How does my server know that a client has disconnected? 【发布时间】:2021-12-22 12:16:45 【问题描述】:

所以我有一个带有选择的 TCP 连接来处理多个客户端。 这些多个客户端相互聊天,具有独立于服务器的 UDP 连接。 服务器保留所有已连接客户端的列表,并在新客户端到达或断开连接时通知每个客户端。

我有一个工作代码。 我不明白客户端的代码是如何将断开连接信息发送到服务器的。因为服务器收到客户端断开连接的信息。但是如何

server.py:

import pickle
import select
import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
address = ('0.0.0.0', 7000)
server.bind(address)
print('Starting up on %s port %s' % address)

input_sockets = [server]
output_sockets = []
clients = []

server.listen(10)
i = 0

while True:
    readable, writable, exceptional = select.select(input_sockets, output_sockets, input_sockets)

    for s in readable:

        if s is server:

            i = i+1
            client_socket, client_address = s.accept()
            print('New connection from client ' + str(i) + ' with address: ' + str(client_address))

            client_socket.send(pickle.dumps(clients))
            for client in input_sockets:
                if client is not server:
                    client.send(pickle.dumps(client_address))

            input_sockets.append(client_socket)
            clients.append(client_address)

        else:

            client_address = s.getpeername()
            print("Client with address '" + str(client_address) + "' disconnected")
            clients.remove(client_address)
            input_sockets.remove(s)

            for client in input_sockets:
                if client is not server:
                    client.send(pickle.dumps(client_address))

            s.close()

client.py

import socket
import pickle
import threading
import select


def chat(udp_sock):
    global done
    while not done:
        message = input()
        if message == "QUIT":
            done = True
        else:
            for client in clients:
                udp_sock.sendto(message.encode('utf-8'), client)


done = False
server_address = ('127.0.0.1', 7000)

s_tcp = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s_udp = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

s_tcp.connect(server_address)

clients_data = s_tcp.recv(1024)
clients = pickle.loads(clients_data)

s_udp.bind(s_tcp.getsockname())

reading = threading.Thread(target=chat, args=(s_udp,))
reading.start()

while not done:
    r, w, e = select.select([s_tcp, s_udp], [], [], 1)
    for s in r:
        if s == s_tcp:
            addr = s_tcp.recv(1024)
            addr = pickle.loads(addr)
            if addr in clients:
                clients.remove(addr)
                print("Client " + str(addr) + " has disconnected.")
            else:
                clients.append(addr)
                print("Client " + str(addr) + " is now connected.")
        if s == s_udp:
            msg, addr = s_udp.recvfrom(1024)
            msg = msg.decode()
            print("[" + str(addr) + "]: " + str(msg))

reading.join()
s_tcp.close()
s_udp.close()

    enter code here

【问题讨论】:

这里有两种可能性: 1. 您编写了代码,并让它工作,但神奇地忘记了您将与服务器断开连接的子句放在哪里。 2. 你从网上拿了随机代码,不明白它的作用,并试图将它拼凑起来做你想做的事,现在不明白它的作用。无论这两者中哪一个是正确的,您都没有在此处提供调试信息,我们甚至无法尝试了解您不理解代码的哪一部分。在撰写本文时,您的问题是“为我解释这段代码?”这是题外话。 【参考方案1】:
for s in readable:

    if s is server:
        ...
    else:

        client_address = s.getpeername()
        print("Client with address '" + str(client_address) + "' disconnected")
        clients.remove(client_address)
        input_sockets.remove(s)

select 表明它可以从客户端套接字读取时,服务器只是断开客户端的连接。由于客户端从不通过 TCP 连接向服务器发送任何内容,因此客户端套接字可读的唯一情况是客户端断开连接时。在这种情况下,客户端套接字上的 recv 将返回 '',即没有数据表明套接字已断开连接。 T

因此,客户端只需断开 TCP 连接,即可向服务器发出客户端已完成的信号。这是通过关闭套接字在代码中显式完成的,但也会在客户端退出时隐式完成。

s_tcp.close()

【讨论】:

以上是关于我的服务器如何知道客户端已断开连接?的主要内容,如果未能解决你的问题,请参考以下文章

django 频道如何知道客户端已断开连接?

如果已断开连接的客户端已重新连接,Python3就会知道

如果服务器断开我的连接,如何检测客户端?

C# TcpListener如何知道客户端已经断开连接

C# TcpClient 不会注册断开连接

如何在WebSocket的服务器侧检测客户端的断开连接