1

我正在用 Python 编写一个游戏服务器,并使用 Faucet Networking 插件在 Game Maker 中编写一个游戏客户端(尽管这无关紧要)。每次玩家移动时,客户端都会向服务器发送一条UPDATEXY消息,并且客户端中有消息聊天的东西。当有 2 个客户端连接到服务器时,客户端似乎会收到消息超载(进一步进入运行时,聊天消息显得更慢,并且玩家落后于实际其他玩家所在的位置)。我相信这是因为客户端无法以它们流入的速度处理消息,所以我在客户端中实现了一个功能,它将所有消息转储到接收缓冲区中,并忽略它们。这似乎有效,但玩家会猛烈地抽搐。这个问题有什么“干净的解决方法”吗?

顺便说一句,我使用的协议是 TCP。这是 TCP 本身的问题还是我只是用错了?切换到 UDP 有帮助吗?

谢谢。

编辑:请求代码,所以你去服务器:

def sendmsg(msgtype, msg, conn, args=None):
    if msgtype == MSG_PLAYER_ASSIGN_ID:
        dataload = struct.pack('!hhh', MSG_STARTBYTE, msgtype, msg)
        conn.send(dataload)

    elif msgtype == MSG_PLAYER_UPDATEXY: #This will only ever be broadcasted
        #print("Sending xy from " + str(args['pid']))
        dataload = struct.pack('!hhhhh', MSG_STARTBYTE, msgtype, args['pid'], msg[0], msg[1])
        conn.send(dataload)

    elif msgtype == MSG_ASKFORLIST:
        players = msg
        for player in players:
            if args['pid'] != player.pid and player.dead == False:
                dataload = struct.pack('!hhhh' + str(len(str(player.name))) + "s", MSG_STARTBYTE, MSG_PLAYERENTRY, player.pid, len(str(player.name)), player.name.encode())
                conn.send(dataload)
                loginfo("Sent a player")

^这只是几个包,还有更多,但它们都非常像那些

在这里,你去客户端:

if msgtype == MSG_PLAYER_UPDATEXY
{
if tcp_receive(serversocket, 6){
pidtoupdate = read_short(serversocket)
//show_message(string(pidtoupdate))
if objNewNetProcessor.pid != pidtoupdate
{
xtoupdate = read_short(serversocket)
ytoupdate = read_short(serversocket)
playertoupdate = ds_map_find_value(global.players, string(pidtoupdate))
if playertoupdate != objChar
{
playertoupdate.y = ytoupdate
playertoupdate.x = xtoupdate}
}}}

if msgtype == MSG_CHAT
{
if tcp_receive(serversocket, 4){
fromperson = read_short(objNewNetProcessor.serversocket)
strlen = read_short(objNewNetProcessor.serversocket)
tcp_receive(objNewNetProcessor.serversocket, strlen)
chatmsg = read_string(objNewNetProcessor.serversocket, strlen)
display_chat(fromperson, chatmsg)
}}

^抱歉,这完全是乱码,现在只是临时代码。它也只是几个数据包,它在该代码下面处理更多,尽管它们看起来都相似。

4

2 回答 2

1

如果尚未准备好发送大数据块(大约 100 到 1000 字节),TCP 通常配置为在发送任何内容之前等待大约 200 毫秒。这称为 Nagle 算法。当客户端尝试以 60fps(~16ms 周期)发送更新时,这意味着您将爆发大量过时的数据。

可以关闭 Nagle 缓冲,但 UDP 更适合实时游戏中的持续位置更新等情况。

也就是说,我希望一台速度相当快的机器上的 Python 服务器能够跟上 2 个客户端的更新,所以可能还有其他事情发生。

于 2012-05-15T22:04:55.270 回答
1

通常这应该可以正常工作,我怀疑这是 CPU 负载高的问题 - 每秒 60 次更新相当多,但只有两个客户端连接,不应该有那么多流量需要处理。相比之下,Gang Garrison 2 每秒只使用 30 次更新,但使用一台不错的 PC,它可以在服务器上处理 20 名玩家。检查任务管理器中的客户端和服务器 CPU 负载以确保安全,但我不认为这是问题所在。

如果清除客户端上的“积压”使它们赶上来,这可能不是网络速度或服务器的问题,但是使用Wireshark记录客户端上的流量以查看一切是否看起来仍然很有价值预期的(例如,数据包以预期的速率发送和接收,并且是均匀定时的)。

由于客户端上似乎有积压:客户端是否尝试在每个步骤中使用尽可能多的消息,还是仅在一个服务器步骤中使用消息?如果您每个客户端步骤只处理一个服务器步骤,那么任何不可避免发生的连接中断都会导致您永久落后,这似乎与您描述的一致。

Russell Borogove 也给了你一个很好的指导,一定要确保在服务器上每个与游戏相关的套接字上禁用 Nagle 算法(=启用 tcp_nodelay)。Faucet 默认执行此操作。

于 2012-05-20T10:25:49.910 回答