帮助与文档

您的位置  :  

游戏服务器如何发送UDP消息给客户端?

文字出处:未知  |  作者:admin  |  发布时间:2021-12-16 10:01
  这个问题是从自己测试一个c#的UDP聊天.exe开始的。当我把这个.exe运行于有公网IP的游戏服务器,通过本地pc运行另一个.exe向该服务器发送消息。远程桌面连接上,游戏服务器的.exe很快就收到了这条消息,并且显示了发来消息的本地pc的IP和端口。但是游戏服务器尝试输入该IP向本地PC发消息时,本地PC却收不到信息...后来去查了pc和游戏服务器防火墙入墙出墙规则没有问题,再遇到了几篇类似的UDP服务器发送不了消息给客户端的问题,重新了解到NAT的转发机制和端口映射的一些知识,在家里设置了路由器的端口映射,再次尝试还是失败了...对这个概念理解的很模糊
 
  之前用c++ TCP服务器进行部署的时候,从来没考虑过这个公网IP服务器无法发送消息给内网的情况,以为所谓网页上随便搜索到的IP可以当游戏服务器的公网IP使用....而TCP服务器传回客户端,使用的是socket方法,比如windows的 WSA_Send,c#的TcpClient send,AsyncSend等,绕开了本地pc IP的问题。
 
游戏服务器如何发送UDP消息给客户端?
 
  但是如果我想使用UDP游戏服务器,向游戏客户端发送消息,那该怎么处理,有没有一个好的例子?年末还要考计网的我羞愧万分!希望能得到指点!
 
  这个问题其实很简单,仅仅是一个NAT(Network Address Translation)地址转换的问题。对应OSI参考模型的第三层(网络层)、第四层(传输层),这是网络工程师的专业范畴。
 
  NAT不对称性
 
  NAT不对称表现为:客户端主动联系服务器,可以。服务器主动联系客户端,不可以!比如你手机开机时,你的微信客户端可以主动发起连接微信登录服务器,这一点问题没有,微信服务器却无法主动发起一个连接你的微信客户端。
 
  有同学说这不对,之所以微信服务器无法主动发起一个连接你的微信客户端,是因为客户端没有一个正在监听(Listening)端口号。如果国内服务器知道客户的监听端口号,比如6666,那么服务器完全是可以主动发起向端口6666建立连接的!
 
  仿佛说的头头是道,但是经不起推敲。微信服务器知道你微信客户端的公网IP地址吗?
 
  不知道,假设微信服务器提前知晓客户端公网IP = 6.6.6.6,然后微信服务器联系6.6.6.6:6666,是不是就可以了?
 
  很抱歉地通知你,服务器的报文到达客户端网络NAT设备时,就会被扔进垃圾桶!
 
  为了不被扔进垃圾桶,需要在NAT设备需要配置一条NAT转换关系,将手机私有IP 与公网IP做一个替换。忙到现在终于可以了,微信服务器可以主动与客户端建立连接了。可是有没有想过,为了建立这一个连接,花费了多少配置代价?
 
  代价太大,实在是不值得。况且全球10亿+客户端,个个都这么配置,是不是太笨了?
 
  微信服务器是怎么实现可以主动给客户端发消息的呢?
 
  建立一个TCP长连接,这个长连接只要用户在线,就永远是活着的。那么服务器在任何时候,都可以将自己的消息顺着这个保活的逻辑信道发给客户端。这个TCP长连接,永远都是客户端主动发起,服务器端被动接受连接。
 
  如何让一个TCP长连接一直是活的?建立好之后,把它晾在一边不管不问,可以永恒保活吗?
 
  不可以。因为NAT设备上动态创建的NAT表会超时删除。一旦被删除,这个长连接也就名存实亡了,服务器发出的消息永远也无法到达客户端。
 
  如何让长连接保活呢?
 
  很简单,周期性发送Keepalive消息,只要保证在NAT表超时之前,刷新了定时器即可。以上就是微信长连接、以及如何维护好长连接。那么UDP如何维持一个长连接呢?
 
  同理可得,只要在消息层面周期性交换Keepalive消息,不让NAT表消失即可。忘记说了,UDP流量所对应的NAT表条目生命周期,远远要小于TCP的,所以在客户端发消息给服务器的1-2分钟之内,服务器如果不发消息给客户端,那么NAT表会超时删除。为了能够顺利通过防火墙的层层过滤,服务器端发出的消息,在四元组方面要与客户端四元组相匹配,不匹配也是到不了客户端的。