首页 > 解决方案 > 为什么与服务器的连接关闭?

问题描述

我正在学习如何在 Python 中为游戏创建服务器。

最终,我们进入下面的这个循环。我用注释替换了不相关的代码以进行演示。它会持续运行,直到从服务器收到某个回复(if split_reply[2] == "established":),或者直到玩家按下按钮将他们带到上一个菜单。

def app_host():
    server_started = False
    connective_state = 'none'
    connect = True
    # stuff happening
    while connect:
        if not server_started:
            server = Server()
            host_address, host_port = server.get_host()
            server_started = True
            connective_state = 'host'
            net = Network(host_address, host_port)
        else:
             client_word = str(net.id) + ":" + "connective state" + ":" + connective_state
             reply = net.send(client_word)
             split_reply = reply.split(":")
             if split_reply[0] == net:
                 if split_reply[2] == "established":
                     connective_state = "established host"
                     app_setup()
             # other stuff happening
    if intro:
        app_intro()

服务器类如下:

class Server:

    def __init__(self):
        self.s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.currentId = "0"
        self.connective_states = ["none", "none"]
        self.server_ip = socket.gethostbyname(socket.gethostname())

        try:
            self.s.bind((self.server_ip, 0))  # Binding to Port 0 allows the OS to select an available port
        except socket.error as e:
            print(str(e))

        self.server_port = self.s.getsockname()[1]

        self.s.listen(2)
        print(f"Server hosted on {self.server_ip}:{self.server_port}.")

        thread = threading.Thread(target=self.run_server, args=())
        thread.daemon = True  # Daemonize thread (if the game exits, shut down the server)
        thread.start()

    def run_server(self):
        while True:
            conn, addr = self.s.accept()
            print(f"Connected to {addr[0]}:{addr[1]}.")

            start_new_thread(self.threaded_client, (conn,))

    def get_host(self):
        return self.server_ip, self.server_port

    def threaded_client(self, conn):
        conn.send(str.encode(self.currentId))
        currentId = "1"
        while True:
            try:
                data = conn.recv(2048)
                reply = data.decode('utf-8')
                if not data:
                    conn.send(str.encode("Goodbye"))
                    break
                else:
                    print("Received: " + reply)
                    split_reply = reply.split(":")
                    socket_id = int(split_reply[0])

                    # The ifs below should have no effect on this issue, you can ignore them
                    if split_reply[1] == "connective state":
                        self.connective_states[socket_id] = split_reply[2]

                    if self.connective_states == ["host", "client"] or ["client", "host"]:
                    #if "host" in connective_states and "client" in connective_states:
                        print(f"Connective states are: {connective_states}")
                        reply = str(socket_id) + ":" + "connective state" + ":" + "established"
                        print(reply)
                        print("Connection established !")

                    elif split_reply[1] == "socket":
                        if split_reply[2] == "disconnect":
                            print(f"Received request to disconnect socket {split_reply[0]}.")
                            conn.close()

                conn.sendall(str.encode(reply))
            except:
                break
        print("Connection Closed")
        conn.close()

网络类是:

class Network:

    def __init__(self, address, port):
        self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.host = address

        self.port = port
        self.addr = (self.host, self.port)
        self.id = self.connect()

    def connect(self):
        self.client.connect(self.addr)
        return self.client.recv(2048).decode()

    def send(self, data):
        try:
            self.client.send(str.encode(data))
            reply = self.client.recv(2048).decode()
            return reply
        except socket.error as e:
            return str(e)

一件事是,我曾经将服务器类作为脚本,threaded_client(conn)作为唯一的函数,作为子进程运行;那会很好用。但是,此方法以某种方式到达终点(print("Connection Closed")并关闭连接。

这是为什么?

服务器启动后连接丢失。

标签: python-3.xsocketsserver

解决方案


好吧,不完全是解决这个特定问题的答案。但是,它解决了设置服务器的一般问题的答案。

我刚刚将我的 server.py 从一个类更改为一个脚本:

import socket
from _thread import *
import threading


s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
currentId = "0"
connective_states = ["none", "none"]
server_ip = socket.gethostbyname(socket.gethostname())

try:
    s.bind((server_ip, 0))  # Binding to Port 0 allows the OS to select an available port
except socket.error as e:
    print(str(e))

server_port = s.getsockname()[1]
s.listen(2)
print(f"Server hosted on {server_ip}:{server_port}.")


def get_host():
    return server_ip, server_port


def threaded_client(conn):
    global currentId, connective_states
    conn.send(str.encode(currentId))
    currentId = "1"
    #reply = ''
    while True:
        try:
            data = conn.recv(2048)
            reply = data.decode('utf-8')
            if not data:
                conn.send(str.encode("Goodbye"))
                break
            else:
                print("Received: " + reply)
                split_reply = reply.split(":")
                socket_id = int(split_reply[0])

                if split_reply[1] == "connective state":
                    connective_states[socket_id] = split_reply[2]

                #if connective_states == ["host", "client"] or ["client", "host"]:
                if "host" in connective_states and "client" in connective_states:
                    print(f"Connective states are: {connective_states}")
                    reply = str(socket_id) + ":" + "connective state" + ":" + "established"
                    print(reply)
                    print("Connection established !")

                elif split_reply[1] == "socket":
                    if split_reply[2] == "disconnect":
                        print(f"Received request to disconnect socket {split_reply[0]}.")
                        conn.close()


            conn.sendall(str.encode(reply))
        except:
            break
    print("Connection Closed")
    conn.close()


def run_server():
    thread = threading.Thread(target=start_threaded_client, args=())
    thread.daemon = True  # Daemonize thread (if the game exits, shut down the server)
    thread.start()


def start_threaded_client():
    while True:
        conn, addr = s.accept()
        print(f"Connected to {addr[0]}:{addr[1]}.")

        start_new_thread(threaded_client, (conn,))

然后,通过将 server.py 导入我的主文件,defs 之前的代码会自动运行。我可以以某种方式使用这个技巧if __name__ == '__main__':来阻止这种形式的发生,但我现在不在乎。然后,我只使用 server.run_server()。


推荐阅读