命令行控制台服务器概述
使用控制台远程控制游戏服务器
有时当你不在特殊计算机之前时,命令行控制台控制服务器是非常有用的。由于服务器确定时会有用,这个主机与该服务器控制地不同的情况下就会有用了。或者或许你有许多服务器需要控制,你想要通过一个脚本控制这些服务器。ConsoleServer,CommandParserInterface,和TransportInterface是三个一起工作类满足这些要求。、
ConsoleServer
ConsoleServer类,在ConsoleServer.h中可以找到,包含了CommandParserInterface类的列表,使用ConsoleServer::AddCommandParser()函数加入。每一个游戏tick通过调用ConsoleServer::Update(),所有的CommandParserInterface类处理所有的进来的输入信息。
CommandParserInterface
命令解析器是一个类,它可以操作命名的注册命令集。CommandParserInterface是一个一个基类,从这个基类你应该为每一个功能解析器派生功能。例如,RakNetCommandParser.h暴露了在RakPeerInterface中可以调用的函数。RakNetTransportCommandParser暴露处理RakNetTransport类的函数,这个类事实上被ConsoleServer用于发送数据。
TransportInterface
TransportInterface类提供了函数给ConsoleServer发送字符串。当前有TransportInterface类的两个实现:TelnetTransport和RakNetTransport。TelnetTransport使用TCPInterface.h来回复给一个远端Telnet终端。RakNetTransport通过RakPeer实例发送字符串,需要使得secure connections可用。
将它们放到一起
来自CommandConsoleServer中的例子
ConsoleServer consoleServer;
TelnetTransport tt;
RakNetCommandParser rcp;
LogCommandParser lcp;
consoleServer.AddCommandParser(&rcp);
consoleServer.AddCommandParser(&lcp);
consoleServer.SetTransportProvider(ti, port);
lcp.AddChannel("TestChannel");
while (1)
{
lcp.WriteLog("TestChannel", "Test of logger");
consoleServer.Update();
// Game loop here
}
事实上这个是很简单的。你有一个控制台服务器实例,传输接口的实例(Either TelnetTransport 或 RakNetTransport),以及你的命令解析。调用ConsoleServer::AddCommandParser用于每一个parser,ConsoleServer::SetTranseportProvider()用于telnet或RakNet,每一个tick调用ConsoleServer::Update()一次。这里我还加了一个输出信道到LogCommandParser,每一个tick输出到log一次。
假设服务器已经启动,你可以按照如下步骤连接:
从start菜单启动telnet
使用telnet连接到服务器
系统应该处理每一件事情
RakNetTransport
安全控制台连接
Telnet很容易连接,但是并不安全。如果你想要发送密码或其他机密数据,你应该在服务器上使用RakNetTransport来代替Telnet。这个形成了一个另外的命令解析器,RakNetTransportCommandParser,这个命令解析器可以增加功能,在RakNetTransport内部改变RakPeer实例的密码。这种方法非常适合于远程用户在没有连接到游戏时连接到命令解析器,游戏和命令行解析器可以有不同的密码。
对于客户端,CommandConsoleClient例子是一个控制台应用程序的实现,这个应用程序使用RakNet连接到RakNetTransport。
创建你自己的命令解析器
预定义命令或将命令字符串直接传递到你的脚本系统中
要增加一个新的命令解析器,首先从CommandParserInterface派生一个类,就如RakNetCommandParser.h中的做法一样。你需要重写(覆盖)OnCommand,GetName,和SendHelp方法。此外,任何与你的游戏通信的函数,例如SetGamePointer()或SetLogger(),你应该你自己增加他们。
1. 在新类的构造函数中,在添加每一个你想要添加的命令时,调用RegisterCommand方法,如下是RakNetCommandParser.cpp中的实例:
RegisterCommand(4, "Startup","( unsigned short maxConnections, int _threadSleepTimer, unsigned short localPort, const char *forceHostAddress );");
第一个参数,4,是传递给函数的参数数量。第二个参数,”Startup”是命令的名字,会在命令列表缩略显示中显示出来。第三个参数,”unsigned short maxConnections…”,定义了helpString,这个字符串是在对一个特别的命名命令调用了help时显示。
给出语法格式,ConsoleServer会验证传递参数的正确数,当调用一个特殊命令时这并不是应该有的情况,那么给用户返回错误信息。
2. 在OnCommand()方法中,将命令字符串与你注册的命令进行对比,采取合适的响应动作。
if (strcmp(command, "Startup")==0)
{
SocketDescriptor socketDescriptor((unsigned short)atoi(parameterList[1]), parameterList[3]);
ReturnResult(peer->Startup((unsigned short)atoi(parameterList[0]), atoi(parameterList[2]), &socketDescriptor, 1), command, transport, systemAddress);
}
OnCommand方法的返回结果值当前并没有使用,因此仅仅返回true即可。
ReturnResult是一个函数,可以有选择地调用该函数,它将给请求系统返回一个字符串。
3. 实现GetName()方法,返回命令解析器的名字。这个名字会在命令解析器列表中显示。
4. 实现SendHelp()方法,当你查询你自己的特殊解析器时,它可以返回一些额外的信息。如果你的解析器由于前置条件失败,不能够运行,那比较好的做法是返回一个通知信息,以便调用者可以了解情况。
未知或可变参数数
将CommandParserInterface::VARIABLE_NUMBER_OF_PARAMETERS作为第一个参数传递给RegisterCommand()方法。在这种情况下,RegisterCommand()会验证参数的有效数。是否在OnComand()方法中处理在这种情况下出现的错误,依据你的需求。
直接字符串解析
如果你不想ConsoleServer为你解析传递进来的字符串,使用参数originalString传递给OnCommand方法。例如,如果你控制脚本系统,你可能希望直接将字符串传递进去。
修改描绘器
如果你想要使用其他的分隔符分割命令而不是使用空格,或者使用引号以外的标记分割字符串,定义可以在CommandServer.cpp中找到。如下
#define COMMAND_DELINATOR ' '
#define COMMAND_DELINATOR_TOGGLE '"'
By 北洋小郭
转载请注明出处,请勿用于商业用途,谢谢!