65.9K
CodeProject 正在变化。 阅读更多。
Home

游戏服务器扫描器

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.29/5 (7投票s)

2004 年 8 月 23 日

1分钟阅读

viewsIcon

55014

downloadIcon

2497

用于在局域网中查找游戏服务器的端口扫描器。

屏幕截图

Sample Image - gfxscan.jpg

引言

gfxscan 是一个简单的端口扫描器,旨在搜索局域网中运行游戏服务器的远程计算机。

它异步地向子网中的特定端口(例如反恐精英的 27015 端口)上的所有 IP 发送简单的 UDP 请求。然后解析响应以获取服务器的详细信息。可以发出许多额外的请求以了解有关游戏的更多信息,我稍后会发布这些信息。

我尝试找到一个简单的局域网端口扫描器并进行了大量 Google 搜索,但没有找到任何。因此,我决定编写自己的游戏服务器扫描器。

遇到的问题

主要问题是减少读取调用等待时间。我通过将选项 System::Net::Sockets::SocketOptionName::ReceiveTimeout 设置为 1000 来解决这个问题。

sock->SetSocketOption(System::Net::Sockets::SocketOptionLevel::Socket, 
      System::Net::Sockets::SocketOptionName::ReceiveTimeout,1000);

可以使用 sock->set_Blocking(false) 来取消套接字的阻塞特性。

主要代码片段

  1. 创建 UDP 套接字,启动一个新线程以读取来自找到服务器的主机的响应,以及向子网中的主机发送 UDP 请求
    void scanServers(String* ip[],int prt,int count)
    {
      boolRead =1;
      port = prt;
      sock = new Socket(AddressFamily::InterNetwork, 
                 SocketType::Dgram,ProtocolType::Udp);
      readThread = new Thread(new ThreadStart(this,read));
      readThread->Start();
      Byte msg[]= System::Text::Encoding::ASCII->GetBytes("xxxxinfo\0");
      Byte msg2[]= new Byte[1000];
      msg[0] = 0xff;
      msg[1] = 0xff;
      msg[2] = 0xff;
      msg[3] = 0xff;
      for(int i=0;i<count;i++)
      {
        IPAddress* ipAdd = IPAddress::Parse(ip->GetValue(i)->ToString());
        IPEndPoint* endPoint = new IPEndPoint(ipAdd,port);
        EndPoint* senderRemote = __try_cast<EndPoint*>(endPoint);
        try
        {
          sock->SendTo(msg, 0, msg->Length, SocketFlags::None, endPoint);
        }
        catch ( SocketException* se )
        {
          //MessageBox::Show(se->Message,"exception while sending",
               MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
        }
      }
    }
  2. 设置非阻塞和超时选项,从同一套接字读取主机数据,解码消息,然后将其发送到显示以正确显示消息
    void read()
    {
      IPEndPoint* sender = new IPEndPoint(IPAddress::Any, port);
      EndPoint* senderRemote = __try_cast<EndPoint*>(sender);
      Byte msg2[]= new Byte[1000];
      sock->set_Blocking(false);
      sock->SetSocketOption(System::Net::Sockets::SocketOptionLevel::Socket,
               System::Net::Sockets::SocketOptionName::ReceiveTimeout,1000);
    
      while(boolRead==1)
      {
        try 
        {
          int iR = sock->ReceiveFrom(msg2, 0, msg2->Length, 
                        SocketFlags::None, &senderRemote);
          Char chars[] = new Char[2000];
          Decoder* d = Encoding::UTF8->GetDecoder();
          int charLen = d->GetChars(msg2, 0, msg2->Length, chars, 0);
          String* str = new String(chars); 
          parseAndAdd(str);
        }
        catch (SocketException* se)
        {
          MessageBox::Show(se->Message,"exception while sending", 
                  MessageBoxButtons::OK, MessageBoxIcon::Exclamation);
        }
      }
      this->labelStatus->set_Text(new String("Scan Complete."));
      this->labelStatus->Invalidate();
    }

我希望创建一个类,以便提供一个整洁的接口来查找局域网中的游戏服务器,并为它们提供更多游戏信息,例如玩家数量、正在玩的游戏地图以及每个玩家的状态。

在那之前,祝您游戏愉快!

© . All rights reserved.