【问题标题】:Socket sending data twiceSocket发送数据两次
【发布时间】:2021-02-11 01:15:54
【问题描述】:

我在开发多人游戏时遇到了数据会被发送两次的错误。我和一个玩家一起工作得很好,但是一旦另一个玩家加入服务器,数据就会被发送两次。如果只连接了一个客户端,则从服务器接收到的数据是这样的:{"player locations": [[1, 84, 100, false, ["n", "a", "m", "e"]]]}。这是连接两个客户端时从服务器接收到的数据:

{"player locations": [[1, 80, 102, true, ["P", "l", "a", "y", "e", "r", "O", "n", "e"]], [2, 57, 102, false, ["P", "l", "a", "y", "e", "r", "T", "w", "o"]]]}{"player locations": [[1, 80, 102, true, ["P", "l", "a", "y", "e", "r", "O", "n", "e"]], [2, 57, 102, false, ["P", "l", "a", "y", "e", "r", "T", "w", "o"]]]}

这是服务器发送的数据

b'{"player locations": [[1, 80, 102, true, ["P", "l", "a", "y", "e", "r", "O", "n", "e"]], [2, 57, 102, false, ["P", "l", "a", "y", "e", "r", "T", "w", "o"]]]}'

这是 server.py 文件的代码:

IMPORTS/SETUP -------------------------------------------------------------------------------------------------------- #
import socket, sys, json
import threading

# FUNCTIONS ------------------------------------------------------------------------------------------------------------ #

def get_ip_port(path):
    with open(path, "r") as ipf:
        ipf_data = ipf.read()
        ipf.close()
    data_split = ipf_data.split(":")
    return [data_split[0],int(data_split[1])]

print(get_ip_port("serverip.txt"))

def update_clients(updatemessage):
    """
    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:
    :return:
    """
    # player key structure: {playerid:[[x,y],flip,name]}
    update_data = json.loads(updatemessage)
    playerid = [key for key in update_data.keys()][0]
    update_lst = update_data[playerid]
    playerid = update_lst[0]
    #print(update_lst)
    #print(playerid)
    print(players)

    if playerid == 0:
        return
    playermap[playerid][0][0] = update_lst[1]
    playermap[playerid][0][1] = update_lst[2]
    playermap[playerid][1] = update_lst[3]
    playermap[playerid][2] = update_lst[4]

    remove = []
    for player_socket in players:
        update = {'player locations':[]}
        for key, value in playermap.items():
            update['player locations'].append([key, value[0][0], value[0][1], value[1], value[2]])
        try:
            print(json.dumps(update).encode())
            player_socket.sendall(json.dumps(update).encode())
        except Exception as e:
            remove.append(player_socket)
            print(e)
            continue
        for r in remove:
            players.remove(r)

def client_thread(conn, player_id):
    while True:
        try:
            recvdata = conn.recv(bufsize)
            if recvdata:
                update_clients(recvdata)
            else:
                break
        except Exception as e:
            print(e)
            break

    playermap.pop(player_id)
    players.remove(conn)
    conn.close()

# VARIABLES ------------------------------------------------------------------------------------------------------------ #

MAX_PLAYER_COUNT = 15

ipport = get_ip_port("serverip.txt")
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(tuple(ipport))
s.listen(MAX_PLAYER_COUNT+1)
bufsize = 2048

global playermap
global players
players = []
playermap = {}
playerstartpos = [50,50]

print("Server has started, waiting for connections.")

#player key structure: {playerid:[[x,y],flip,name]}

# SERVER LOOP ---------------------------------------------------------------------------------------------------------- #
while True:
    conn, addr = s.accept()
    print(f"Connection from {addr}")
    players.append(conn)
    playerid = len(players)
    playermap[playerid] = [[playerstartpos[0], playerstartpos[1]],False,""]
    conn.send(json.dumps({"id update": playerid}).encode())

    pthread = threading.Thread(target=client_thread, args=[conn,playerid])
    pthread.start()

这是从服务器接收数据的client.py文件中的代码:

    # player key structure: {playerid:[[x,y],flip,name]}
    # update = {'player locations':[[value.id, value.x, value.y, value.flip, value.name]]}
    ins, outs, ex = select.select([n.socket], [], [], 0)
    for in_ in ins:
        data = in_.recv(2048)
        print(data.decode() + "\n")
        if data:
            try:
                socket_event = json.loads(data)
            except Exception as e:
                print(e)
            event_type = [key for key in socket_event.keys()][0]
            event_data_lst = socket_event[event_type]
        if event_type == 'id update':
            player.id = event_data_lst
        if event_type == 'player locations':
            #socket_event.pop(0)
            players = []
            for splayer in event_data_lst:
                if splayer[0] != player.id:
                    socket_player = Player((splayer[1], splayer[2]), (15,37), splayer[4], splayer[0])
                    socket_player.flip = splayer[3]
                    players.append(socket_player)
                #else:
                #    player.x = splayer[1]
                #    player.y = splayer[2]

【问题讨论】:

    标签: python sockets networking pygame


    【解决方案1】:

    这可能是问题所在:

     for player_socket in players:
            update = {'player locations':[]}
            for key, value in playermap.items():
                update['player locations'].append([key, value[0][0], value[0][1], value[1], value[2]])
            try:
                print(json.dumps(update).encode())
                player_socket.sendall(json.dumps(update).encode())
    

    所以基本上发生的事情是你从所有player_socket 发送,这应该没问题,但是当有两个玩家时,其中两个循环几乎并行运行,这意味着你从每个套接字发送两次(希望你理解)你应该让这个for 循环排除发件人

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-12
      • 1970-01-01
      • 2019-10-10
      相关资源
      最近更新 更多