Python - [Errno 10054] 远程主机强行关闭现有连接 - 发送腌制数据问题 [英] Python - [Errno 10054] An existing connection was forcibly closed by the remote host - sending pickled data issues
问题描述
我遵循了一个在线教程,该教程展示了如何制作一个石头剪刀布游戏,该游戏可以处理连接到服务器的多个客户端,从而允许多人游戏.游戏运行正常,所以我尝试对不同的游戏使用相同的网络逻辑,但我在那里遇到了一些错误.特别是在使用 send
函数时:使用 send
函数时,我得到一个 EOFError: Ran out of input
错误.在这篇文章中 在线游戏给出错误("ConnectionAbortedError: [WinError 10053] " 我发现了一个假设的修复程序,即发送函数会等待直到它接收到所有数据,因为它有时在接收腌制数据时可能会出现问题.
I followed an online tutorial that showed how to make a rock paper scissors game that can handle multiple clients connecting to a server, allowing multiplayer. The game works so I tried to use the same network logic for a different game but I ran into some errors there. Particularly when using the send
function: Using the send
function I get an EOFError: Ran out of input
error. In this post Online game give the error "("ConnectionAbortedError: [WinError 10053] " I found a supposed fix where the send function waits until it has received all of the data, as it sometimes may have issues when receiving pickled data.
但是,当我用新的 send2
函数(临时名称)替换 send
函数时,我遇到了不同的错误.即:[Errno 10054] 一个现有的连接被远程主机强行关闭.
However, when I replace the send
function with the new send2
function (temporary name) I run into different errors. Namely: [Errno 10054] An existing connection was forcibly closed by the remote host.
已解决,请参阅以下段落:
SOLVED, SEE FOLLOWING PARAGRAPh:
本质上,我想要做的是用更好的发送函数替换我的发送函数(它也接收数据),该函数发送腌制数据并接收确切数量的发送信息.
Essentially, what I'm trying to do is replacing my send function (which also receives data) by a better send function that sends pickled data and receives the exact amount of sent information.
def send(self, data):
try:
self.client.send(pickle.dumps(data))
return pickle.loads(self.client.recv(2048))
except socket.error as e:
print(e)
# source: https://stackoverflow.com/questions/62361900/online-game-give-the-error-connectionabortederror-winerror-10053
def send2(self, data):
data_to_send = pickle.dumps(data)
data_size = struct.pack( '!I', len(data_to_send))
try:
self.client.send(data_size)
self.client.send(pickle.dumps(data))
package = self.receive()
return package
except socket.error as e:
print(e)
def receive(self):
packet = None
buffer = bytes()
expected = -1
print("receiving stuff")
while len(buffer) < 4:
print("received a buffer")
try:
partial_data = self.client.recv(4 - len(buffer))
if partial_data:
buffer.append(partial_data)
if len(buffer) == 4:
expected = struct.unpack('!I', buffer)
except Exception as e:
print(e)
break
# If we received a buffer size, try to receive the buffer
if expected > 0:
buffer = bytes()
while len(buffer) < expected:
try:
partial_data = self.client.recv(expected - len(buffer))
if partial_data:
buffer.append(partial_data)
# Have we received the full data-set yet?
if len(buffer) == expected:
packet = pickle.loads(buffer)
except:
break
print(packet)
return packet
我假设我忽略了一些非常简单的事情.如果需要,我可以发布运行游戏的 4 个 .py 文件.我所需要的只是创建一个更好的 send
函数,当它处理发送有时不值得泡菜的数据时,它不会使客户端崩溃.
I'm assuming I'm overlooking something incredibly easy. If needed, I can post the 4 .py files that run the game. All I need is to create a better send
function that doesn't crash the client when it is dealing with sending data that is sometimes not pickle-worthy.
Server.py 代码
Server.py code
import socket
import pickle
from _thread import *
import sys
sys.path.append("C:/Program Files/Hero Realms/Multiplayer/")
from game import Game
from network import Network
server = "" # this is defined but I removed it for this page
port = 5555
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((server, port))
except socket.error as e:
print(e)
s.listen(2)
print("Waiting for a connection, Server Started")
connected = set()
games = {}
id_count = 0
def threadedClient(conn, p, game_id):
global id_count
conn.send(str.encode(str(p)))
reply = ""
while True:
try:
#data = pickle.loads(conn.recv(4096))
data = Network.receive(s)
print(data)
# check if the game still exists
if game_id in games:
game = games[game_id]
if not data:
break
else:
if data == "reset":
game.resetWent()
elif data != "get":
game.play(p, data)
reply = game
conn.sendall(pickle.dumps(reply))
else:
break
except:
break
print("Lost connection")
try:
print("Closing game", game_id)
del games[game_id]
except:
pass
id_count -=1
conn.close()
while True:
conn, addr = s.accept()
print("Connected to: ", addr)
id_count += 1
p = 0
game_id = (id_count - 1) // 2
if id_count % 2 == 1:
games[game_id] = Game(game_id)
print("Creating a new game...")
else:
games[game_id].ready = True
p = 1
start_new_thread(threadedClient, (conn, p, game_id))
客户端.py
import pygame
import sys
sys.path.append("C:/Program Files/Hero Realms/Multiplayer/")
from network import Network
import pickle
pygame.font.init()
pygame.init()
width = 700
height = 700
win = pygame.display.set_mode((width, height))
pygame.display.set_caption("Client")
class Button:
def __init__(self, text, x, y, color):
self.text = text
self.x = x
self.y = y
self.color = color
self.width = 150
self.height = 100
def draw(self, win):
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height))
font = pygame.font.SysFont("comicsans", 40)
text = font.render(self.text, 1, (255, 255, 255))
win.blit(text, (self.x + round(self.width / 2) - round(text.get_width() / 2), self.y + round(self.height / 2) - round(text.get_height() / 2)))
def click(self, pos):
x1 = pos[0]
y1 = pos[1]
if self.x <= x1 <= self.x + self.width and self.y <= y1 <= self.y + self.height:
return True
else:
return False
def redrawWindow(win, game, p):
win.fill((128, 128, 128))
if not(game.connected()):
font = pygame.font.SysFont("comicsans", 80)
text = font.render("Waiting for Player...", 1, (255, 0, 0), True)
win.blit(text, (width / 2 - text.get_width() / 2, height / 2 - text.get_height() / 2))
else:
font = pygame.font.SysFont("comicsans", 60)
text = font.render("Your Move", 1, (0, 255, 255))
win.blit(text, (80, 200))
text = font.render("Opponents", 1, (0, 255, 255))
win.blit(text, (380, 200))
move1 = game.getPlayersMove(0)
move2 = game.getPlayersMove(1)
if game.bothWent():
text1 = font.render(move1, 1, (0, 0, 0))
text2 = font.render(move2, 1, (0, 0, 0))
else:
if game.p1_went and p == 0:
text1 = font.render(move1, 1, (0, 0, 0))
elif game.p1_went:
text1 = font.render("Locked in", 1, (0, 0, 0))
else:
text1 = font.render("Waiting...", 1, (0, 0, 0))
if game.p2_went and p == 1:
text2 = font.render(move2, 1, (0, 0, 0))
elif game.p2_went:
text2 = font.render("Locked in", 1, (0, 0, 0))
else:
text2 = font.render("Waiting...", 1, (0, 0, 0))
if p == 1:
win.blit(text2, (100, 350))
win.blit(text1, (400, 350))
else:
win.blit(text1, (100, 350))
win.blit(text2, (400, 350))
for btn in btns:
btn.draw(win)
pygame.display.update()
btns = [Button("Rock", 50, 500, (0, 0, 0)), Button("Scissors", 250, 500, (255, 0, 0)), Button("Paper", 450, 500, (0, 255, 0))]
def main():
run = True
clock = pygame.time.Clock()
n = Network()
player = int(n.getP())
print("You are player ", player)
while run:
clock.tick(60)
try:
game = n.send2("get")
except:
run = False
print("Couldn't get game")
break
if game.bothWent():
redrawWindow(win, game, player)
pygame.time.delay(500)
try:
game = n.send2("reset")
except:
run = False
print("Couldn't get game")
break
font = pygame.font.SysFont("comicsans", 90)
if (game.winner() == 1 and player == 1) or (game.winner() == 0 and player == 0):
text = font.render("You won!", 1, (255, 0, 0))
elif game.winner() == -1:
text = font.render("Tie game!", 1, (255, 0, 0))
else:
text = font.render("You lost", 1, (255, 0, 0))
win.blit(text, (width / 2 - text.get_width() / 2, height / 2 - text.get_height() / 2))
pygame.display.update()
pygame.time.delay(2000)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
pygame.quit()
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
for btn in btns:
if btn.click(pos) and game.connected():
if player == 0:
if not game.p1_went:
n.send2(btn.text)
else:
if not game.p2_went:
n.send2(btn.text)
redrawWindow(win, game, player)
def menuScreen():
run = True
clock = pygame.time.Clock()
while run:
clock.tick(60)
win.fill((128, 128, 128))
font = pygame.font.SysFont("comicsans", 60)
text = font.render("Click to play!", 1, (255, 0, 0))
win.blit(text, (100, 200))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
run = False
if event.type == pygame.MOUSEBUTTONDOWN:
run = False
main()
while True:
menuScreen()
推荐答案
我终于完成了我最初想做的事情.我想编写一个发送函数,发送 X 数量的腌制数据,同时接收函数接收 X 数量的腌制数据,而不会在收到太小而无法腌制的数据时抛出错误.
I managed to finally accomplish what I wanted to do in the first place. I wanted to write a send function that sent out X amount of pickled data alongside a receive function that received X amount of pickled data without throwing errors when it received data that was too small to be pickled.
请参阅 send_data
和 receive_data
函数以了解 network.py
中的解决方案.服务器文件 server.py
也需要这些函数,尽管略有不同.因此,在您的客户端文件中,您应该使用 network.send_data
函数将数据从客户端发送到服务器.
See the send_data
and the receive_data
functions for the solution in network.py
. The server file server.py
requires these functions as well although slightly different. In your client file you should thus make use of the network.send_data
function to send data from the client to the server.
network.py
import socket
import pickle
HEADERSIZE = 10
class Network:
def __init__(self):
self.client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.server = "enter server address"
self.port = 5555
self.addr = (self.server, self.port)
self.p = self.connect()
def getP(self):
return self.p
def connect(self):
try:
self.client.connect(self.addr)
return self.client.recv(2048).decode()
except:
pass
# works but only sends and receives string encoded data without a buffer
def send1(self, data):
try:
self.client.send(str.encode(data))
return pickle.loads(self.client.recv(2048))
except socket.error as e:
print(e)
# works but only sends and receives pickled data without a buffer
def send2(self, data):
try:
self.client.send(pickle.dumps(data))
return pickle.loads(self.client.recv(2048))
except socket.error as e:
print(e)
# this is the function you should use, it uses a receive function that has a buffer
# and ensures that you receive ALL the information that you sent without throwing errors
def send_data(self, data):
data_to_send = pickle.dumps(data)
data_size = bytes(f'{len(data_to_send):<{10}}', "utf-8")
try:
self.client.send(data_size + data_to_send)
package = self.receive_data()
return package
except socket.error as e:
print(e)
def receive_data(self):
full_msg = b''
new_msg = True
while True:
msg = self.client.recv(16)
if new_msg:
msglen = int(msg[:HEADERSIZE])
new_msg = False
full_msg += msg
if len(full_msg)-HEADERSIZE == msglen:
data = pickle.loads(full_msg[HEADERSIZE:])
break
return data
server.py
import socket
import pickle
from _thread import *
import sys
from game import Game
server = "enter server address"
port = 5555
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
s.bind((server, port))
except socket.error as e:
print(e)
s.listen(2)
print("Waiting for a connection, Server Started")
connected = set()
games = {}
id_count = 0
HEADERSIZE = 10
def receive_data(sock):
full_msg = b''
new_msg = True
while True:
msg = sock.recv(16)
if new_msg:
msglen = int(msg[:HEADERSIZE])
new_msg = False
full_msg += msg
if len(full_msg)-HEADERSIZE == msglen:
data = pickle.loads(full_msg[HEADERSIZE:])
break
return data
def send_data(clientsocket, data):
data_to_send = pickle.dumps(data)
data_size = bytes(f'{len(data_to_send):<{10}}', "utf-8")
try:
clientsocket.send(data_size + data_to_send)
except socket.error as e:
print(e)
def threadedClient(conn, p, game_id):
global id_count
conn.send(str.encode(str(p)))
reply = ""
while True:
try:
data = receive_data(conn)
# check if the game still exists
if game_id in games:
game = games[game_id]
if not data:
break
else:
if data == "reset":
game.resetWent()
elif data != "get":
game.play(p, data)
reply = game
send_data(conn, reply)
else:
break
except Exception as e:
print("Failed try")
print(e)
break
print("Lost connection")
try:
print("Closing game", game_id)
del games[game_id]
except:
pass
id_count -=1
conn.close()
while True:
conn, addr = s.accept()
print("Connected to: ", addr)
id_count += 1
p = 0
game_id = (id_count - 1) // 2
if id_count % 2 == 1:
games[game_id] = Game(game_id)
print("Creating a new game...")
else:
games[game_id].ready = True
p = 1
start_new_thread(threadedClient, (conn, p, game_id))
这篇关于Python - [Errno 10054] 远程主机强行关闭现有连接 - 发送腌制数据问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!