【发布时间】:2015-10-12 02:23:03
【问题描述】:
我正在尝试连接到使用Steam RCON Protocol 的 Steam 游戏服务器的 RCON。我用谷歌搜索了一下,发现有人为这个确切目的做了一段时间的以下代码。在检查了一段时间的代码后,它确实看起来应该可以工作,但由于某种原因它没有。
代码如下:
class RconSteam {
/*
* The constants are the packet types.
*/
static final int EXECUTE_COMMAND_PACKET = 2;
static final int AUTHORIZATION_PACKET = 3;
static final int AUTHORIZATION_RESPONSE = 2;
static final SocketAddress serverAddress = new InetSocketAddress("IP ADDRESS", PORT);
static final String rconPassword = "password";
static InputStream inputStream;
static OutputStream outputStream;
/**
* Starts the application.
*
* @param args
* command-line arguments
* @throws IOException
*/
public static void main(String[] args) {
try {
/*
* Prepare the socket and retrieve the streams.
*/
Socket socket = new Socket();
socket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
socket.connect(serverAddress);
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
/*
* Authorize the user and then send commands. Multiple commands can
* be sent, but the user may need to be reauthorized after some
* time.
*/
boolean auth = sendAuthorizationPacket();
if (auth) {
if(sendCommand("serverchat HELLO"))
{
System.out.println("WINNER");
} else {
System.out.println("FAILED");
}
} else {
System.out.println("OH NOES");
}
/*
* Close the socket once its done being used.
*/
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Sends a command to the server. The user must be authorized for the server
* to execute the commands.
*
* @param command
* the command
* @throws IOException
*/
static boolean sendCommand(String command) throws IOException {
byte[] packet = createPacket(2000, EXECUTE_COMMAND_PACKET, command);
outputStream.write(packet);
/*
* The server responds to command execution packets as well, but those
* responses are not very important. However, it may be worthwhile to
* check if the server actually responded with text. If a response
* contains no textual message, that usually means that the user needs
* to be reauthorized with the server. Another way to check if the user
* needs to be reauthorized is simply by joining the server and seeing
* if the commands sent have any effect.
*/
ByteBuffer response = parsePacket();
int type = response.getInt(8);
int id = response.getInt(4);
System.out.println(type);
System.out.println(id);
return ((type == EXECUTE_COMMAND_PACKET) && (id) == 2000);
}
/**
* Sends an authorization packet to the server.
*
* @return whether or not the user was authorized by the server
* @throws IOException
*/
static boolean sendAuthorizationPacket() throws IOException {
/*
* Create the authorization packet and send it.
*/
byte[] packet = createPacket(1000, AUTHORIZATION_PACKET, rconPassword);
outputStream.write(packet);
/*
* Read the response (the first packet is a junk one) and check if the
* server authorized the user. The user is authorized if the server
* responds with the same packet ID as the one sent, which is 1000 in
* this case.
*/
ByteBuffer response = parsePacket();
return (response.getInt(8) == AUTHORIZATION_RESPONSE) && (response.getInt(4) == 1000);
}
/**
* Creates an RCON packet.
*
* @param id
* the packet ID (not an opcode)
* @param type
* the type
* @param command
* the command
* @return the bytes representing the packet
*/
static byte[] createPacket(int id, int type, String command) {
ByteBuffer packet = ByteBuffer.allocate(command.length() + 16);
packet.order(LITTLE_ENDIAN);
packet.putInt(command.length() + 12).putInt(id).putInt(type).put(command.getBytes()).putInt(0);
return packet.array();
}
/**
* Parses the next packet from the socket's input stream.
*
* @return the next packet
* @throws IOException
*/
static ByteBuffer parsePacket() throws IOException {
/*
* Read the length of the packet.
*/
byte[] length = new byte[4];
inputStream.read(length);
/*
* Create a buffer to contain the packet's payload.
*/
ByteBuffer packet = ByteBuffer.allocate(4120);
packet.order(LITTLE_ENDIAN);
packet.put(length);
/*
* Read the payload.
*/
for (int i = 0; i < packet.getInt(0); i++) {
packet.put((byte) inputStream.read());
}
return packet;
}
}
程序在程序中运行没有错误,但是它似乎只在第一次发送数据包时从服务器获得响应。我可以成功地对服务器进行身份验证并从服务器获得响应,但是第二个命令似乎没有得到正确响应并关闭连接(?)。
我尝试测试以立即跳到serverchat HELLO 命令,但我确实从服务器收到了我未通过身份验证的响应。
我想看看 Wireshark 发生了什么,但我不知道该怎么做。我有限的wireshark经验告诉我发送第二个数据包后出现了问题。
此时,我不完全确定问题是否出在此代码中,或者是否与服务器或网络相关(如果是,抱歉在 SO 上发布)。不过其他工具似乎工作正常,所以我猜它与代码有关。
任何帮助表示赞赏!
编辑:如果屏幕太小,请链接到屏幕截图:http://i.imgur.com/5CZXLaT.png
编辑 2:更新后的代码:
class RconSteam {
/*
* The constants are the packet types.
*/
static final int EXECUTE_COMMAND_PACKET = 2;
static final int AUTHORIZATION_PACKET = 3;
static final int AUTHORIZATION_RESPONSE = 2;
static final SocketAddress serverAddress = new InetSocketAddress("IP HERE", PORT);
static final String rconPassword = "password\0";
static InputStream inputStream;
static OutputStream outputStream;
/**
* Starts the application.
*
* @param args
* command-line arguments
* @throws IOException
*/
public static void main(String[] args) {
try {
/*
* Prepare the socket and retrieve the streams.
*/
Socket socket = new Socket();
socket.bind(new InetSocketAddress(InetAddress.getLocalHost(), 0));
socket.connect(serverAddress);
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
/*
* Authorize the user and then send commands. Multiple commands can
* be sent, but the user may need to be reauthorized after some
* time.
*/
boolean auth = sendAuthorizationPacket();
if (auth) {
if(sendCommand("serverchat HELLO"))
{
System.out.println("WINNER");
} else {
System.out.println("FAILED");
}
} else {
System.out.println("OH NOES");
}
/*
* Close the socket once its done being used.
*/
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Sends a command to the server. The user must be authorized for the server
* to execute the commands.
*
* @param command
* the command
* @throws IOException
*/
static boolean sendCommand(String command) throws IOException {
byte[] packet = createPacket(2000, EXECUTE_COMMAND_PACKET, command+'\0');
outputStream.write(packet);
/*
* The server responds to command execution packets as well, but those
* responses are not very important. However, it may be worthwhile to
* check if the server actually responded with text. If a response
* contains no textual message, that usually means that the user needs
* to be reauthorized with the server. Another way to check if the user
* needs to be reauthorized is simply by joining the server and seeing
* if the commands sent have any effect.
*/
ByteBuffer response = parsePacket();
int type = response.getInt(8);
int id = response.getInt(4);
System.out.println(type);
System.out.println(id);
return ((type == EXECUTE_COMMAND_PACKET) && (id) == 2000);
}
/**
* Sends an authorization packet to the server.
*
* @return whether or not the user was authorized by the server
* @throws IOException
*/
static boolean sendAuthorizationPacket() throws IOException {
/*
* Create the authorization packet and send it.
*/
byte[] packet = createPacket(1000, AUTHORIZATION_PACKET, rconPassword);
outputStream.write(packet);
/*
* Read the response (the first packet is a junk one) and check if the
* server authorized the user. The user is authorized if the server
* responds with the same packet ID as the one sent, which is 1000 in
* this case.
*/
ByteBuffer response = parsePacket();
return (response.getInt(8) == AUTHORIZATION_RESPONSE) && (response.getInt(4) == 1000);
}
/**
* Creates an RCON packet.
*
* @param id
* the packet ID (not an opcode)
* @param type
* the type
* @param command
* the command
* @return the bytes representing the packet
*/
static byte[] createPacket(int id, int type, String command) {
ByteBuffer packet = ByteBuffer.allocate(command.length() + 16);
packet.order(LITTLE_ENDIAN);
//packet.putInt(command.length() + 12).putInt(id).putInt(type).put(command.getBytes()).putInt(0);
packet.putInt(command.length() + 14).putInt(id).putInt(type).put(command.getBytes()).put((byte)0).put((byte)0);
return packet.array();
}
/**
* Parses the next packet from the socket's input stream.
*
* @return the next packet
* @throws IOException
*/
static ByteBuffer parsePacket() throws IOException {
/*
* Read the length of the packet.
*/
byte[] length = new byte[4];
inputStream.read(length);
/*
* Create a buffer to contain the packet's payload.
*/
ByteBuffer packet = ByteBuffer.allocate(4120);
packet.order(LITTLE_ENDIAN);
packet.put(length);
/*
* Read the payload.
*/
for (int i = 0; i < packet.getInt(0); i++) {
packet.put((byte) inputStream.read());
}
return packet;
}
}
【问题讨论】:
标签: java sockets networking tcp packet