Python服务器和游戏客户端:消息超载?

时间:2012-05-15 21:44:48

标签: python sockets tcp game-maker

我正在用Python编写一个游戏服务器,在Game Maker中编写一个带有Faucet Networking插件的游戏客户端(尽管这无关紧要)。每次玩家移动时,客户端都会向服务器发送UPDATEXY消息,并且客户端中有一条消息聊天内容。有两个客户端连接到服务器,似乎客户端的消息过载(进一步进入运行时,聊天消息显得较慢,玩家落后于实际的其他玩家)。我相信这是因为客户端无法以它们流入的速率处理消息,所以我在客户端实现了一个功能,它只会将所有消息转储到接收缓冲区中,并忽略它们。这似乎有效,但玩家会猛烈地猛拉一下。对这个问题有什么“干净的解决方法”,或者从一开始我做错了是一件很重要的事情吗?

顺便说一下,我使用的协议是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)
}}

^对不起,这是一个完整的消息,它现在只是临时代码。它也只是一些数据包,它在该代码之下处理更多,尽管它们看起来都类似于那些。

2 个答案:

答案 0 :(得分:1)

TCP通常被配置为在发送任何内容之前等待大约200ms,如果还没有准备好发送大小的数据块(大约100到1000字节)。这称为Nagle算法。客户试图以60fps(约16ms周期)发送更新,这意味着您将破坏大量过时的数据。

可以关闭Nagle缓冲,但UDP更适合于实时游戏中的常量位置更新等。

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

答案 1 :(得分:1)

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

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

由于客户端上似乎存在积压:客户端是尝试每步消耗尽可能多的消息,还是只消耗一个服务器步骤的消息?如果您每个客户端步骤只处理一个服务器步骤,那么任何不可避免的连接打嗝将导致您永久性地落后,这似乎与您描述的一致。

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