科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件高级WinSock多人游戏编程技术

高级WinSock多人游戏编程技术

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

多人网络游戏中如何避免迟延是一个比较重要的话题。作为多人网络游戏开发者,我们总是努力使事情做得更快,减少迟延以获得更多的带宽。

作者:佚名 来源:论坛 2007年10月20日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
4、连接多播组与接收多播数据包(Joining a Multicast Group and Receiving Multicast Data Packets)

  为了收到发送至多播组的多播数据包,你的游戏需要加入或成为一个多播组的成员。请求成为一个多播组的成员比你想象的要简单的多。首先,你需要绑定你的UDP套接口至一个本地的端口。

  SOCKADDR_IN addrLocal;
  // We want to use the Internet address family
  addrLocal.sin_family = AF_INET;
  // Use any local address
  addrLocal.sin_addr.s_addr = INADDR_ANY;
  // Use arbitrary port - but the same as on other clients/servers
  addrLocal.sin_port = htons(uiPort);
  // Bind socket to our address
  if(SOCKET_ERROR == bind(hUDPSocket, (LPSOCKADDR)&addrLocal,
              sizeof(struct sockaddr)))
    { cout << "Euston, we have a problem"; }
  // Ready to switch to multicasting mode

  然后调用setsockopt(),该函数的原型如下:

  int WSAAPI setsockopt(SOCKET s, int level, int optname,
             const char FAR * optval, int optlen);

  这个函数调用的参数:s为socket句柄、level设置成IPPROTO_IP、optname设置成IP_ADD_MEMBERSHIP、optval是一个指向p_mreq结构体的指针、optlen为长度。其中p_mreq结构体看起来如下:

  struct ip_mreq {
    struct in_addr imr_multiaddr;  /* multicast group to join */
    struct in_addr imr_interface;  /* interface to join on */
  }

  它有两个域,两者都为in_add r结构体:imr_multiaddr 指定跟进多点传送组的地址。而imr_interface指定局部地址INADDR_ANY。

  专门(Class‘D’)为多播组分配地址。范围是从224.0.1.0到239.255.255.255。你可以从目标多播组范围内选择一个作为跟进地址,并且将其放到imr_multiaddr中。整个setsockopt的()调用看起来象这样:

  struct ip_mreq mreq;
  mreq.imr_multiaddr.s_addr = inet_addr("234.5.6.7");
  mreq.imr_interface.s_addr = INADDR_ANY;
  nRet = setsockopt(hUDPSocket, IPPROTO_IP, IP_ADD_MEMBERSHIP,(char*)&mreq, sizeof(mreq));
      
  为了的简洁,我去掉了不少的错误检测代码。这套接口现在将在调用recvfrom()的特殊端口收到派送至多播组的数据包。

  SOCKADDR_IN addrSrc;
  nRet = recvfrom(hUDPSocket, (char *)&Data, sizeof(Data), 0,
          (struct sockaddr*)&addrSrc, sizeof(addrSrc));

  当你和该组结束关系并想离开这个组,只需重复调用使用除IP_ADD_MEMBERSHIP(已被IP_DROP_MEMBERSHIP替换)以外的同类参数。

  nRet = setsockopt(hUDPSocket, IPPROTO_IP, IP_DROP_MEMBERSHIP,
           (char*)&mreq, sizeof(mreq));

  既然我们可以加入一个多播组并且收到发送给他的数据包,逻辑上做这件事就是学习如何发送包至单个多播组。

  5、发送多播数据包(Sending Multicast Data Packets)

  通过调用sendto()函数来实现发送多播数据包,需要指定一个多播组地址作为目标IP地址还有你指定的端口号。这里我们先来了解一下关于IP多播的Winsock选项。(译者:有三个IP多播独有的选项:IP_MULTICAST_TTL,IP_MULTICAST_IF,IP_MULTICAST_LOOP)这里要说的是IP_MULTICAST_TTL选项,它用于设置多播数据的生存时间,默认情况下,TTL的值为1。也就是说多播数据遇到第一个路由器便会被丢弃。假如增大TTL的值,多播数据就可以经历多个路由器传到其他网络。TTL的值是多少,最多就能经过多少个路由器,每过一个路由器,TTL的值就会减一。下面那张表说明了具体情况。

TTL阈值(Threshold) Description
TTL equal to 0 Restricted to the same host
TTL equal to 1 Restricted to the same subnet
TTL equal to 32 Restricted to the same site
TTL equal to 64 Restricted to the same region
TTL equal to 128 Restricted to the same continent
TTL equal to 255 Unrestricted in scope
[ From MSDN ]

  char TTL = 32 ; // Restrict to our school network, for example
  setsockopt(hUDPSocket, IPPROTO_IP, IP_MULTICAST_TTL,
        (char *)&TTL, sizeof(TTL));

  设置好选项了就可以调用sendto()函数发送数据包了。

  SOCKADDR_IN addrDest;
  szHi[50];

  addrDest.sin_family = AF_INET;
  // Target multicast group address
  addrDest.sin_addr.s_addr = inet_addr("234.5.6.7");
  // Port on which client is set to receive data packets
  addrDest.sin_port = htons(uiPort);
  // Something unoriginal to send
  strcpy(szHi,"Hello Multicast Group!");

  nRet = sendto(hUDPSocket, (char *)szHi, sizeof(szHi), 0,
         (struct sockaddr*)&addrDest, sizeof(addrDest));

  到此我们就可以加入多播组,从多播组发送和接收数据,但如何将它应用到我们的游戏中呢?接着看……
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章