我正在学习如何在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()
Server类如下:
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")
并关闭连接。
那是为什么?
答案 0 :(得分:0)
好吧,并非完全是对这个特定问题进行分类的答案。但是,尽管如此,答案还是可以解决设置服务器方面的普遍问题。
我刚刚将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()。