首页 > 解决方案 > 提高套接字速度

问题描述

我正在开发一个带有套接字的多人游戏,并决定测试从另一台机器连接到服务器。我能够连接到服务器,但唯一的问题是有一点延迟。其他玩家会停下来,然后他们会传送回他们应该在的地方。这些不是很大的尖峰,它只会持续大约 4/6 秒,但很明显。我知道当我扩展游戏时,服务器会更慢到几乎无法玩的地步,所以我在这里询问希望找到加速服务器的好方法。我做了一些速度测试,这就是我得到的:

# Buffer recv - 0.015977859497070312
# update_client - typically around 0.00017213821411132812, but sometimes spikes to 9.202957153320312e-05
# sending data - around 0.0001914501190185547, but every other time, it spikes to 8.416175842285156e-05

这不是很多,但它可能会有所帮助。这是上面每个测试的代码。

接收缓冲区代码:

data = ""
recv_data = conn.recv(bufsize)
if recv_data == b'':
    print(f"{player_id} DISCONNECTED")
    break
message_length = int(recv_data[:HEADER_SIZE])
data += recv_data.decode()
while True:
    if len(data)-HEADER_SIZE >= message_length:
        if len(data)-HEADER_SIZE > message_length:
            conn.setblocking(0)
            while True:
                try:
                    extra_data = conn.recv(bufsize)
                    if not extra_data:
                        break
                except:
                    break
            conn.setblocking(1)
        break
    recv_data = conn.recv(bufsize)
    data += recv_data.decode()
data = data[HEADER_SIZE:message_length+HEADER_SIZE]

Update_client 代码(我为每个客户端使用一个新线程)

def update_client(updatemessage,target_socket):
    """
    update_data[0][0] is the player's x pos
    update_data[0][1] is the player's y pos
    update_data[1] is the player's flip bool
    update_data[2] is the player's name str

    :param updatemessage:
    :param target_socket:
    :return:
    """
    
    # player key structure in playermap: {playerid:[[x,y],flip,name,been_hit]}
    update_data = json.loads(updatemessage) # Data received from the passed client
    updates = [key for key in update_data.keys()] # All keys in the dict sent from client
    player_update_lst = update_data[updates[0]] # Player locations update data
    mini_update_lst = update_data[updates[1]] # Mini game update data
    playerid = player_update_lst[0] # The id of the player client sending this data

    if playerid == 0: # Prevent sending data to the server itself
        return
        
    update = {'player locations':[],"mini-update":[]} # Empty update dict
    if start_game and playerid not in updated_clients:
        update["map-update"] = start_game[1]
        updated_clients.append(playerid)
        if sorted([key for key in playermap.keys()]) == sorted(updated_clients):
            print("Clearing")
            start_game.clear()
            updated_clients.clear()
    
    if playerid != 1:
        if playerid not in playermap.keys():
            playerid -= 1
        elif playerid - 1 not in playermap.keys():
            pdata = playermap[playerid]
            playermap.pop(playerid)
            playerid -= 1
            playermap[playerid] = pdata
            update = {"id update":playerid,'player locations':[],"mini-update":[]}
    else:
        if mini_update_lst[2]:
            minigame, minimap = get_minimap()
            update["map-update"] = minimap
            start_game.append(minigame)
            start_game.append(minimap)
            print("starting game")
                        
    # Player locations update stuff
    playermap[playerid][0][0] = player_update_lst[1] # player.x
    playermap[playerid][0][1] = player_update_lst[2] # player.y
    playermap[playerid][1] = player_update_lst[3] # player.flip
    playermap[playerid][2] = player_update_lst[4] # player.name
    playermap[playerid][4] = player_update_lst[5]  # player.been_hit

    # Mini game update stuff
    hit_player = mini_update_lst[0] # hit_player (the id of the player that the client hit)
    if hit_player:
        playermap[hit_player][3] = playermap[playerid][0] # Goes to the id of the hit player in playermap and changes the "False"
                                                          # value at index 3, to the position of the player that hit the other player.
    playermap[playerid][5] = mini_update_lst[1] # player.score (KOTH: The time in seconds the player has been on the platform)

    # Looping over every connected player to send to the selected client. Used for changes to the player's position or look.
    # (by "look", I mean the flip value which flips the player's image, and the hit value which changes the player img's hue)
    score_update_lst = []
    for key, value in playermap.items():
        # key is the player's id
        # value[0][0] is the player's x position
        # value[0][1] is the player's y position
        # value[1] is the player's flip value
        # value[2] is the player's name
        # value[3] is the player's attacker pos value (stores the position of the attacker if hit)
        # value[4] is the player's been_hit value (used for the player flash when hit)
        # value[5] is the player's score value (used for minigames)
        update['player locations'].append([key, value[0][0], value[0][1], value[1], value[2], value[4]])
        score_update_lst.append([value[2],value[5]])
    update["mini-update"].append(score_update_lst)

    # Knockback stuff. If the player has been hit, the position of the attacker will be stored at playermap[playerid][3].
    # If there is data there, the code in the if statement is excuted
    if playermap[playerid][3]:
        update['mini-update'].append(playermap[playerid][3])
        playermap[playerid][3] = False
    else:
        update['mini-update'].append(False)

    # Sending the data to the client, but if there is a error, the client socket is removed
    try:
        #print(json.dumps(update).encode())
        send_data = json.dumps(update)
        target_socket.sendall((f"{len(send_data):<{HEADER_SIZE}}"+send_data).encode())
    except Exception as e:
        print(f"Error: {e}")
        
    return playerid

发送数据代码:

try:
    #print(json.dumps(update).encode())
    send_data = json.dumps(update)
    target_socket.sendall((f"{len(send_data):<{HEADER_SIZE}}"+send_data).encode())
except Exception as e:
    print(f"Error: {e}"

有谁知道如何使这些代码片段更快?如果您需要额外的信息或代码,请随时询问:)。

标签: pythonperformancesocketsnetworking

解决方案


推荐阅读