开发者社区 问答 正文

Python套接字关闭所有连接,而不是只关闭它自己

我正在编写这个简单的多线程套接字程序,它检查数据库中是否存在用户名和密码。 Client.py

import socket
import getpass


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(("127.0.0.1", 1234))

while True:
    command = input(">>")
    case = command.split()
    if case[0] == "bye":
      s.sendall(bytes("close", "utf-8"))
      break

    elif case[0] == "login":
      psswrd = getpass.getpass()
      s.sendall(bytes("login" + " " + case[1] + " " + psswrd, "utf-8"))
      rep = s.recv(2048).decode("utf-8")
      print(rep)

    else:
      print("Wrong command")

s.close()

Server.py

import socket
import threading
from user import User


class ClientThread(threading.Thread):
    def __init__(self, addr, client):
        threading.Thread.__init__(self)
        self.client = client
        print(f" {addr} connected")

    def run(self):
        while True:
            try:

                msg = client.recv(2048).decode("utf-8")
                data = msg.split()

                if data[0] == "close":
                    client.close()
                    break

                elif data[0] == "login":
                    u = User(data[1], data[2])
                    result = u.find_user() //checks if it exists in dtb
                    if result and u.pwd == result[2]:
                        client.sendall(bytes("Login successfully", "utf-8"))
                    else:
                        client.sendall(bytes("Wrong", "utf-8"))
            except:
                break

        print(f"{addr} closed")


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(('127.0.0.1', 1234))

while True:
    s.listen(1)
    client, addr = s.accept()
    newthread = ClientThread(addr, client)
    newthread.start()

每个客户端应该单独行动,但当我尝试与2个客户端,在第一个客户端输入“再见”连接关闭两个连接,而“登录”将只运行为第二个客户端,第一个客户端将被卡住。如果有人能告诉我哪部分做错了,那就太好了 问题来源StackOverflow 地址:/questions/59466993/python-socket-closes-all-connection-instead-of-only-itself

展开
收起
kun坤 2019-12-25 09:35:53 423 分享 版权
阿里云 AI 助理回答

在你的代码中,问题出在服务器端处理客户端连接的方式。当一个客户端发送 "bye" 指令导致其对应的线程结束时,并没有恰当地从监听循环中移除这个客户端的 socket。这最终会导致其他客户端可能遇到异常或行为不正常,因为关闭了一个正在被监听的 socket 可能会影响到其他操作。

为了解决这个问题,你需要确保在接收到 "close" 命令后,不仅关闭与该客户端的连接,还要从监听循环中优雅地退出对应的线程。同时,为了更好地管理多个连接,可以考虑使用 socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) 来允许立即重新绑定到相同的地址和端口。

修改 Server.py 的部分代码如下:

import socket
import threading
from user import User

# 设置SO_REUSEADDR选项,以便能够快速重启服务并重新绑定端口
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('127.0.0.1', 1234))

def handle_client(client_socket, addr):
    try:
        while True:
            msg = client_socket.recv(2048).decode("utf-8")
            if not msg:  # 如果客户端关闭了连接,recv会返回空字符串
                break
            
            data = msg.split()

            if data[0] == "close":
                print(f"{addr} requested close.")
                break

            elif data[0] == "login":
                u = User(data[1], data[2])
                result = u.find_user()  # checks if it exists in dtb
                response = "Login successfully" if result and u.pwd == result[2] else "Wrong"
                client_socket.sendall(bytes(response, "utf-8"))

    except Exception as e:
        print(f"Error in {addr}: {e}")
    finally:
        client_socket.close()
        print(f"{addr} closed")

while True:
    s.listen(1)
    client, addr = s.accept()
    print(f"{addr} connected")
    client_handler = threading.Thread(target=handle_client, args=(client, addr))
    client_handler.start()

这样修改后,每个客户端的连接都会在一个独立的线程中正确处理,当一个客户端发送 "bye" 并断开连接时,不会影响到其他客户端的连接状态。同时,通过设置 SO_REUSEADDR,即使在短时间内有连接关闭,也能迅速重新接受新的连接请求。

有帮助
无帮助
AI 助理回答生成答案可能存在不准确,仅供参考
0 条回答
写回答
取消 提交回答