【问题标题】:How to use a socket without waiting in python如何在不等待python的情况下使用套接字
【发布时间】:2021-08-15 11:41:40
【问题描述】:

我用 Python 创建了一个游戏,该游戏由几条蛇组成,每条蛇都由不同的计算机控制。每台计算机都会向服务器计算机发送蛇所指向的角度。

问题在于命令

client_mess = client_socket.recv(1024)

极大地抑制服务器操作并导致游戏运行非常缓慢。 我正在寻找一种使用用户发送的用户消息的方法,如果自上一个消息以来没有发送任何消息,服务器将使用前一个消息而不等待另一条消息。

这些是我的代码的相关部分:

服务器:

server_socket = socket.socket()
server_socket.bind(('0.0.0.0', 5050))
server_socket.listen(1)
print("Server is up and running")

while not done:
    server_socket = socket.socket()
    server_socket.bind(('0.0.0.0', 5050))
    server_socket.listen(1)
    print("Server is up and running")

客户:

while not done:
    
    for event in pygame.event.get():  # User did something
        if event.type == pygame.QUIT:  # If user clicked close
            done = True  # Flag that we are done so we exit this loop
    siz = type(siz)
    my_socket=socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    my_socket.connect(('127.0.0.1', 5050))

    message = str(siz)

    my_socket.send(message.encode())

【问题讨论】:

  • 您必须搜索的术语是“非阻塞套接字”
  • 我很想解释一下这对我有什么帮助
  • @eliotz 首先不要在主循环的每次迭代中都连接到服务器,只连接一次,这些都是非常无用的 cmets,你也应该提供一个minimal reproducible example,如何“非阻塞套接字”会帮助你吗?他们不会阻塞正在运行你的游戏的线程
  • @MegaIng 这对我没有帮助,即使在“非阻塞套接字”中也必须等待至少一秒钟(这是我的理解)
  • @eliotz 你在哪里读到的。这不是我所知道的。 AFAIK,如果没有要接收的消息,非阻塞套接字会立即返回/引发。他们会尽快返回。

标签: python sockets


【解决方案1】:

您可以在非阻塞模式下使用套接字:

import pygame as pg
import socket

pg.init()

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
client.connect(("localhost", 55555)) # Connect to server
client.setblocking(False) # Prevent socket from waiting for input

W, H = 640, 480
FLAGS = 0

screen = pg.display.set_mode((W, H), FLAGS)
W, H = screen.get_size()

font = pg.font.SysFont("arial", 30)

text = ""

running = True
while running:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False
        elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE:
            running = False

    try:
        raw = client.recv(1024)
    except BlockingIOError:
        pass # No new data. Reuse old data
    else:
        text = raw.decode("utf-8") # New data has arrived. Use it

    screen.fill((0, 0, 0))
    img = font.render(text, True, (255, 255, 255))
    r = img.get_rect(center=(W // 2, H // 2))
    screen.blit(img, r)
    pg.display.update()

这假设一个简单的服务器脚本是这样的:

import socket

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

server.bind(("localhost", 55555))
server.listen()

while True:
    client, address = server.accept()
    print("Connected to", address)
    while True:
        line = input("> ")
        try:
            client.send(line.encode("utf-8"))
        except ConnectionError as e:
            print(e)
            print("Disconnecting")
            client.close()
            break

它将在 pygame 窗口的中心显示您在服务器上输入的任何文本行。


如果您想要相反的情况,即服务器打开 pygame 窗口,您可以使用以下代码:

服务器:

import socket

import pygame as pg

pg.init()

W, H = 640, 480
FLAGS = 0

screen = pg.display.set_mode((W, H), FLAGS)
W, H = screen.get_size()

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("localhost", 55556))
server.listen(1)
server.setblocking(False)
client = None

font = pg.font.SysFont("arial", 30)

text = ""

clock = pg.time.Clock()
running = True
while running:
    for event in pg.event.get():
        if event.type == pg.QUIT:
            running = False
        elif event.type == pg.KEYDOWN and event.key == pg.K_ESCAPE:
            running = False
        elif event.type == pg.VIDEORESIZE:
            screen = pg.display.set_mode(event.size, FLAGS)
            W, H = screen.get_size()
    # Logic
    dt = clock.tick()

    if client is None:
        try:
            client, address = server.accept()
        except BlockingIOError:
            pass
    else:
        try:
            raw = client.recv(1024)
        except BlockingIOError:
            pass
        else:
            text = raw.decode("utf-8")


    # Render
    screen.fill((0, 0, 0))
    img = font.render(text, True, (255, 255, 255))
    r = img.get_rect(center=(W // 2, H // 2))
    screen.blit(img, r)

    pg.display.update()
    pg.display.set_caption(f"FPS: {clock.get_fps():.2f}")

客户

import socket

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

client.connect(("localhost", 55556))

try:
    while True:
        line = input("> ")
        try:
            client.send(line.encode("utf-8"))
        except ConnectionError as e:
            print(e)
            print("Disconnecting")
            break
finally:
    client.close()

如果您希望两者都有 pygames 窗口,我建议您考虑使用多个客户端和一个非 pygame 服务器。但无论如何,类似的代码应该可以工作。

【讨论】:

  • 我需要服务器继续,而不是客户端。有可能吗?
  • @eliotz 你这是什么意思。与我的问题非常相似的代码也允许服务器像这样工作,但这与您的问题不匹配。
  • @eliotz 更新了我的答案
  • 谢谢你,你帮了我很多
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-19
  • 2012-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-01
  • 2016-07-23
相关资源
最近更新 更多