套接字两次发送数据

问题描述

当我遇到一个错误,该错误会将数据发送两次时,我正在从事多人游戏。我在一个播放器上工作得很好,但是一旦另一个播放器加入服务器,数据将被发送两次。如果仅连接了一个客户端,则从服务器接收的数据如下所示:{"player locations": [[1,84,100,false,["n","a","m","e"]]]}。当两个客户端连接时,这是从服务器接收的数据:

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

这是服务器发送的数据

b'{"player locations": [[1,"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,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,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]

解决方法

这可能是问题所在

 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循环将发件人排除在外