Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/sockets/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python服务器和游戏客户端:消息过载?_Python_Sockets_Tcp_Game Maker - Fatal编程技术网

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

Python服务器和游戏客户端:消息过载?,python,sockets,tcp,game-maker,Python,Sockets,Tcp,Game Maker,我正在用Python编写一个游戏服务器,用带有水龙头网络插件的GameMaker编写一个游戏客户端(尽管这不重要)。每次播放器移动时,客户端都会向服务器发送一条UPDATEXY消息,并且客户端中有一条聊天消息。当两个客户端连接到服务器时,客户端似乎被消息超载(进入运行时间后,聊天消息显示较慢,播放机落后于实际的另一个播放机)。我相信这是因为客户端无法以消息流入的速度处理消息,所以我在客户端实现了一个功能,它只会将所有消息转储到接收缓冲区中,并忽略它们。这似乎奏效了,但玩家会猛地乱跳。这个问题有没

我正在用Python编写一个游戏服务器,用带有水龙头网络插件的GameMaker编写一个游戏客户端(尽管这不重要)。每次播放器移动时,客户端都会向服务器发送一条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)
}}

^很抱歉,这完全是一个混乱,这只是暂时的代码。它也只是几个数据包,虽然它们看起来都很相似,但在代码下面它处理的数据包更多。

TCP通常被配置为在发送任何数据之前等待大约200毫秒,如果大小合适的数据块尚未准备好发送(大约100到1000字节)。这被称为Nagle算法。当客户端试图以每秒60帧(约16毫秒)的速度发送更新时,这意味着您将需要大量过时的数据

可以关闭Nagle缓冲,但UDP更适合于实时游戏中的恒定位置更新


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

一般来说,这应该可以正常工作,我怀疑这是CPU负载高的问题-每秒60次更新相当多,但是,由于只有两个客户端连接,因此不应该有太多的流量需要处理。相比之下,Gang Garrison 2每秒只使用30次更新,但有了一台像样的PC,它可以在一台服务器上处理20名玩家。检查TaskManager中的客户端和服务器CPU负载是否安全,但我不认为这是问题所在

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

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


Russell Borogove也给了你一个很好的指针,一定要确保服务器上每个与游戏相关的套接字上都禁用了Nagle的算法(=启用了tcp_nodelay)。水龙头默认是这样做的。

1)没有任何代码就很难调试,2)似乎与消息处理有关,而不是传输,3)与python无关,因为它很可能是客户端。@BluePeppers 1)我认为这更多的是一个理论问题,而不是我的代码问题,但如果你坚持的话,我马上把它贴在这里。2) 我想3)我想知道Python的速度是否与此有关。服务器是否响应每个更新?您知道这些消息的发送速率吗?在客户端开始减速之前需要多长时间?服务器将更新传递给每个连接的客户端。客户端以60fps的帧速率运行,并在播放器每次移动像素时发送UPDATEXY。我从未跟踪过玩家何时开始落后,但当所有玩家都静止不动时,它会再次回到正常速度。是的,python应该能够很好地做到这一点,尽管我希望寻找像gevent这样的解决方案来同时运行多个小Tasklet。如果将客户端更新率降低到,每秒10次(100毫秒周期),还是最终仍会发生?我还没有尝试过。不过我确实试过一次,每5秒清除一次recvbuffer,它起作用了,但会让客户端从过时的位置猛然跳到新的位置。清除接收缓冲区听起来非常危险-如果当时缓冲区中有一条分数消息呢?(或者说水龙头在为你们处理信息边界方面处于较低的水平?)!我每一步只处理一条消息!