游戏服务器查询库(译文)
By robot-v1.0
本文链接 https://www.kyfws.com/games/a-gameserver-query-library-zh/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 9 分钟阅读 - 4499 个词 阅读量 0游戏服务器查询库(译文)
原文地址:https://www.codeproject.com/Articles/8834/A-gameserver-Query-Library
原文作者:Franz Pentenrieder
译文由本站 robot-v1.0 翻译
前言
A library that allows to query nearly all gameserver types
一个可以查询几乎所有游戏服务器类型的库
- 下载源文件27.5 KB(Download source files - 27.5 KB)
- 下载演示项目-16.3 KB(Download demo project - 16.3 KB)
- 下载库和文档-246.9 KB(Download library and documentation - 246.9 KB)
介绍(Introduction)
大多数游戏服务器都支持状态查询,以获取诸如服务器配置或玩家数量之类的信息.有些程序可以查询主服务器,以从游戏服务器接收所有IP并将其列出.最受欢迎的是Gamespy,全视之眼和kQuery.(Most gaming servers support status queries to get information like server configuration or the number of players. There are some programs that query master servers to receive all IPs from the gaming servers and list them. The most popular ones are Gamespy, The All Seeing Eye and kQuery.) 我不打算构建具有相同功能的另一个程序,而是创建一个可以轻松处理的服务器库,以查询服务器并根据您的特殊目的提供其信息.(I did not intend to build another program with just the same functionality, but to create a library that allows easy handling to query the servers and offering their information on your special purpose.)
背景(Background)
状态查询使用特定的协议:最常见的协议是Doom3,Gamespy,Gamespy v2,Half-Life,Quake3,Source(半条命2)和The All Seeing Eye(ASE).这些协议提供的信息基本相同,但结构不同.通常,分为三个部分:(The status queries use specific protocols: the most common are Doom3, Gamespy, Gamespy v2, Half-Life, Quake3, Source (Half-Life 2) and The All Seeing Eye (ASE). These protocols provide basically the same information, but their structure is different. In general, there are three sections:)
资讯(Infos)
基本信息,例如服务器名称,地图名称,最大播放器和密码保护.(The basic information like server name, map name, maximum players and password protection.)
规则(Rules)
详细的服务器信息以及与比赛有关的数据,例如团队或响应时间.(The detailed server information with game specific data like teams or response time.)
玩家们(Players)
服务器上所有播放器的列表.这些信息有很大的不同:不同的协议只有一个共同的球员名称,取决于协议,还有球员的得分,ping或团队.(A list of all players on the server. These information differs a lot: the different protocols have only the player name in common, depending on the protocol there are also the players' score, ping or team.)
协议概述(Protocol Overview)
这是不同协议及其工作方式的简短概述:(Here is a short overview of the different protocols and how they work:)
毁灭战士3(Doom3)
该协议目前仅在所谓的游戏中使用,但可能会在即将基于同一引擎构建的游戏中使用.请求以(This protocol is currently used only in so called game, but will probably be used in upcoming games built on the same engine. The request starts with a) 0xFF 0xFF
,然后是一个简单的(, followed by a simple) getInfo
.服务器响应是一个很大的块,由(. The server response comes in one big block and is separated by) 0x00
.这使得响应看起来像(. That makes the response look like a) Key0x00Value
–服务器信息和播放器信息之间用逗号分隔(– the server information and the player information are separated by a) 0x00
0x00
(双((a double) NULL
).().)
游戏迷(Gamespy)
Gamespy是最古老,使用最广泛的协议之一.它的结构非常简单:要获取服务器的信息,您只需发送一个简单的(Gamespy is one of the oldest and most broadly used protocols. Its structure is very simple: to get the server’s information, you just need to send a simple) \info\
;对于规则,发送(; for the rules, send) \rules\
;对球员来说(; and for the players,) \players\
.您还可以通过发送类似以下内容来组合这些请求(. You can also combine these requests by sending something like) \infos\\players\\rules\
.(.)
响应看起来像(The response looks like) \Key\Value\Key\Value\
,则播放器信息会以整数扩展以对其进行分组.他们看起来像(, the player info is extended with an integer to group them. They look like) \player_0\Name\frags_0\10\ping_0\100\
.这很重要,因为某些服务器会发送所有(. This is important because some servers send all) \player_x\
标志,其次是所有(flags, followed by all) \frags_x\
等等.(and so on.)
Gamespy v2(Gamespy v2)
名称表示,Gamespy v2是Gamespy协议的修订版.它与第一个版本的不同之处在于,它通过字节值而不是字符串来管理信息.所有请求均以(The name indicates, Gamespy v2 is the revision of the Gamespy protocol. It differs from the first version by managing information more with byte values than with strings. All requests begin with a) 0xFE 0xFD 0x00
,然后是用作ping值的字符串.现在,我们再追加三个字节,代表我们想知道的信息:第一个字节用于服务器信息,第二个字节用于规则,第三个字节用于玩家.您可以用(, followed by a string that is used as a ping value. Now we append three more bytes which stand for the information we want to know: the first byte for server information, the second for rules and the third for players. You can set them with) 0x00
对于否或(for NO or) 0xFF
是的.响应的结构与Doom3中的相同.(for YES. The structure of the response is the same as in Doom3.)
半衰期(Half-Life)
请求以(The request starts with a) 0xFF 0xFF 0xFF 0xFF
, 其次是(, followed by) details
,(,) rules
要么(or) players
,因此与Gamespy v2几乎相同,但带有字符串.响应的结构与Doom3中的相同.(, so it is pretty much the same as in Gamespy v2, but with strings. The structure of the response is the same as in Doom3.)
雷神之锤3(Quake3)
该请求类似于<半条命>:我们从(The request is similar to Half-Life: we start with a) 0xFF 0xFF 0xFF 0xFF
,然后是字符串(, followed by the string) getstatus
.响应包括多行文本中的所有信息,并且可以通过简单的字符串解析进行处理.第一行可以忽略,第二行以与Gamespy中相同的格式提供服务器信息,(. The response includes all information in multiple text lines and can be handled with simple string parsing. The first line can be ignored, the second provides the server information in the same format as in Gamespy, () \Key\Value\Key\Value\
).以下几行以表格的形式表示玩家信息,每行一位玩家(). The following lines represent the player information, one player per line, in the form) Scores Ping „Playername“
.(.)
来源(半条命2)(Source (Half-Life 2))
请求结构几乎与以前的Half-Life协议中的结构相同:只有字符串被替换为单个字节.查询现在开始于(The request structure is nearly the same as in the former Half-Life protocol: only the strings are replaced with single bytes. The query now starts with) 0xFF 0xFF 0xFF 0xFF
, 其次是(, followed by) 0x54
有关服务器信息,(for the server information,) 0x55
对于规则和(for the rules and) 0x56
播放器信息.响应的结构与Doom3中的相同.(for the player information. The structure of the response is the same as in Doom3.)
全视之眼(ASE)(The All Seeing Eye (ASE))
同名程序的协议是最复杂且很少使用的协议.要求很简单(The protocol to the homonymous program is the most complex and also the rarely used one. The request is a simple) s
,但不同于所有其他协议.查询必须发送到服务器端口+ 123,因此不要发送到游戏服务器端口.响应有点困难,因为它没有分隔符:结构为"字节字符串字节字符串",其中字节表示下一个字符串的长度(该字节是自包含的).服务器和播放器信息之间的分隔符是一个空字符串,因此它是字节本身的长度-一个简单的(, but different from all other protocols. The query must be sent to the server port + 123, so don’t send to the game server port. The response is a little bit more difficult, because it has no separators: The structure is „Byte String Byte String“, in which the byte represents the length of the next string, (the byte is self-including). The separator between the server and player information is an empty string, so it’s the length of the byte itself - a simple) 0x01
.播放器信息看起来很相似,但是通过使用标志来指示包含哪些信息,以一个额外的字节开头.我不再赘述该协议,目前仅使用该协议的游戏是GTA和Farcry.(. The player information looks similar, but starts with an extra byte by using the flags telling which information is included. I do not describe this protocol any further, the only games currently using this protocol are GTA and Farcry.)
有关所有这些协议的出色文档和示例,请参见新闻组.(An excellent documentation and samples for all of these protocols can be found in the newsgroups) dev.int64(dev.int64) 和(and) 开发查询(dev.kquery) ,这是我在创建此库时使用的.(, which I used while creating this library.)
使用代码(Using the Code)
使用该库非常简单.首先,将其包含在您的项目中,然后按如下所示简单地调用它:(Using the library is very simple. First, include it in your project, and then simply call it as shown:)
GameServer server = new GameServer( "192.168.0.15", 27960, GameType.Quake3 );
Server.QueryServer(); // this may take a while
QueryServer()
从服务器获取所有信息.根据超时时间,这可能需要一段时间.您可以使用(gets all the information from the server. Depending on the timeout, this may take a while. You can change this with the) Timeout
属性.(property.)
Server.Timeout = 1500; // in milliseconds
基本信息可用于属性和集合,具体取决于要查询的协议.并非所有值都已设置.以下是所有图表:(The basic information is available over properties and collections, depending on which protocol you are querying. Not all values are set. Here are the diagrams for all of them:)
|
|使用(Using the) Players
财产,你可以得到一个(property, you can get a) PlayerCollection
包含以下数据:(containing the following data:)
的(The) Parameters
属性包含一个(property contains a) StringCollection
来自服务器的所有信息.这些值在很大程度上取决于所使用的协议!(with all information from the server. The values strongly depend on the protocols being used!)
连接到服务器(Connecting to Servers)
完整的连接和解析过程通过抽象协议类进行处理.这是主要的连接部分:(The complete connection and parsing process is handled through the abstract protocol class. Here is the main connection part:)
protected void Connect( string host, int port )
{
_serverConnection = new Socket( AddressFamily.InterNetwork,
SocketType.Dgram, ProtocolType.Udp );
_serverConnection.SetSocketOption( SocketOptionLevel.Socket,
SocketOptionName.ReceiveTimeout, _timeout );
IPAddress ip;
try
{
ip = IPAddress.Parse( host );
}
catch( System.FormatException )
{
ip = Dns.Resolve( host ).AddressList[0];
}
_remoteIpEndPoint = new IPEndPoint( ip, port );
}
服务器通讯(Server Communication)
通信始终使用方法提供的UDP(The communication always uses UDP supplied by the methods) Socket.SendTo()
和(and) Socket.ReceiveFrom()
.(.)
_readBuffer = new byte[100 * 1024]; // 100kb should be enough
EndPoint _remoteEndPoint = (EndPoint)_remoteIpEndPoint;
_packages = 0;
int read = 0, bufferOffset = 0;
// Request
_sendBuffer = System.Text.Encoding.Default.GetBytes( request );
_serverConnection.SendTo( _sendBuffer, _remoteIpEndPoint );
...
read = _serverConnection.ReceiveFrom( _readBuffer, ref _remoteEndPoint );
大多数服务器发送的软件包的最大长度为1400到1500字节.对于长状态信息,该内存不足以将其发送到一个程序包中.通常,它们适合放入两个小包中. UDP是无状态连接,因此我们必须实现如何处理这些多包以及如何合并它们.(Most servers send packages with a maximum length of 1400 to 1500 bytes. For long status information, this is not enough memory to send it in one package. Usually, they fit into two packets. UDP is a stateless connection, so we must implement how to handle these multi-packages and how to merge them.)
半衰期(Half-Life)
在<半条命>中,这些UDP包以9字节长的标头开头,与单包响应不同.第九位告诉我们响应包括多少个软件包,以及我们当前正在处理哪个软件包.(In Half-Life, these UDP-packages start with a 9 byte-long header, different from single-package responses. The ninth position is telling us how many packages the response includes, and which package we are currently working on.)
Gamespy v1和v2(Gamespy v1 and v2)
所有Gamepy响应均以键/值方案为基础,因此,如果我们以正确的顺序合并它们并不重要.协议本身很聪明,可以始终在分隔符处而不是在值内进行拆分,因此我们可以简单地将它们附加在末尾(All Gamespy responses are built in a Key/Value scheme, so it doesn’t really matter if we merge them in the right order. The protocol itself is smart enough to always split at a separator and not inside a value, so we can simply attach them at the end of the) readBuffer
.(.)
解析响应(Parsing the Response)
解析由a分隔的字符串的主要部分(The main part of parsing the strings that are separated by a) NULL
字节(0x00):(byte (0x00):)
protected string ReadNextParam()
{
string temp = "";
for ( ; _offset < _readBuffer.Length; _offset++ )
{
if ( _readBuffer[_offset] == 0 )
{
_offset++;
break;
}
temp += (char)_readBuffer[_offset];
}
return temp;
}
字符串分隔的响应更加简单:(String-separated responses are even more simple:)
AddParams( ResponseString.Split( '\\' ) );
//...
protected void AddParams( string[] parts )
{
if ( !IsOnline )
{
return;
}
string key, val;
for ( int i = 0; i < parts.Length; i++ )
{
if ( parts[i] == "" )
{
continue;
}
key = parts[i++];
val = parts[i];
// Gamespy uses this
if ( key == "final" )
{
break;
}
if ( key == "querid" )
{
continue;
}
_params[key] = val;
}
}
我避免解释如何解析ASE协议,因为它无法100%工作.我缺少一些很好的文档,似乎除了我之外,还有很多人也认为这样做不值得.(I avoided explaining how to parse the ASE protocol, because it doesn’t work 100%. I’m missing some good documentation, and it seems that many people besides me are also thinking that it’s not worth the work.)
链接(Links)
我对这些家伙感激不尽.有关更多信息,请检查以下页面:(I can’t thank enough these guys. For more information, check these pages:)
- 查询(kQuery) -免费软件服务器浏览器(- a freeware server browser)
- 开发查询(dev.kQuery) -jQuery开发人员中心(- the developer center of kQuery)
- dev.int64(dev.int64) -文档和用C编写的查询库(- Documentation and a query library written in C)
- UT2003游戏服务器状态(UT2003 Gameserver Status)
概要(Summary)
我了解了一些有关UDP协议的知识,并使用了以前从未使用过的类和方法,例如(I learned something about UDP protocol and used classes and methods I never used before, like the) BitConverter()
,因此我认为值得进行这项工作.我希望该库对您将来的项目有用.(, so I think it was worth the work. I hope this library can be useful in your future projects.)
执照(License)
本文没有附带任何明确的许可,但可能在文章文本或下载文件本身中包含使用条款.如有疑问,请通过下面的讨论区与作者联系.(This article has no explicit license attached to it, but may contain usage terms in the article text or the download files themselves. If in doubt, please contact the author via the discussion board below.) 可以找到作者可能使用的许可证列表(A list of licenses authors might use can be found) 这里(here) .(.)
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
C# .NET .NET1.1 Dev 新闻 翻译