I have been working on a java program that basically acts like Minechat(text-based app to just view chat.) I have never really worked with networking too much, so the issue is figuring out how to send packets correctly. I am currently at the position of creating the handshake with the server. After hours of research, I have come up with the following code, but it always runs into the "Failed! (Exception)" message. To me, everything looks correct, but for all I know it could be 100% wrong. If someone could point out what I'm doing wrong here, I'd really appreciate it.
For reference, feel free to use this and this.
public static void main(String[] args) throws IOException {
host = new InetSocketAddress("162.244.165.111", 48040);
socket = new Socket();
System.out.println("Connecting...");
socket.connect(host, 3000);
System.out.println("Done!");
System.out.println("Making streams...");
output = new DataOutputStream(socket.getOutputStream());
input = new DataInputStream(socket.getInputStream());
System.out.println("Done!");
System.out.println("Attempting handshake... "+host.getAddress().toString().substring(1));
byte[] msg = ("47;"+host.getAddress().toString().substring(1)+";"+host.getPort()+";2;").getBytes(Charset.forName("UTF-16"));
output.writeInt(msg.length+Integer.valueOf(0x00));
output.writeByte(0x00);
output.write(msg);
output.flush();
try {
if (input.readByte() != 0x02)
System.out.println("Failed!");
else
System.out.println("Done!");
} catch (EOFException e) {
System.out.println("Failed! (Exception)");
}
}
EDIT: More research suggests I use a Byte array, but this confuses me on how to represent a string and using strings is required?
If you are the host, you can either connect to it by typing the public IP or by simply typing 'localhost' if your server is running on the computer you play Minecraft with.
The Minecraft server accepts connections from TCP clients and communicates with them using packets. A packet is a sequence of bytes sent over the TCP connection.
Hosting your own server on Minecraft Java Edition allows you to play in the same world as others at the same time – whether that's for PVP battles, build competitions, manhunts, or just surviving side-by-side. There are a few different ways to host your own Minecraft server, depending on your skill level.
Looking at this page http://wiki.vg/Protocol it looks like your not writing enough data nor in the right order. You also need to be using varint which is a special type of data representation of an integer.
Relevant links to this issue:
C->S : Handshake State=1
C->S : Request
S->C : Response
C->S : Ping
S->C : Pong
C is client and S is server
Using the wiki and the provided code samples I modified your code to follow the entire status request.
public static void main(String [] args) throws IOException {
String address = "162.244.165.111";
int port = 48040;
InetSocketAddress host = new InetSocketAddress(address, port);
Socket socket = new Socket();
System.out.println("Connecting...");
socket.connect(host, 3000);
System.out.println("Done!");
System.out.println("Making streams...");
DataOutputStream output = new DataOutputStream(socket.getOutputStream());
DataInputStream input = new DataInputStream(socket.getInputStream());
System.out.println("Done!");
System.out.println("Attempting handshake... "+host.getAddress().toString());
byte [] handshakeMessage = createHandshakeMessage(address, port);
// C->S : Handshake State=1
// send packet length and packet
writeVarInt(output, handshakeMessage.length);
output.write(handshakeMessage);
// C->S : Request
output.writeByte(0x01); //size is only 1
output.writeByte(0x00); //packet id for ping
// S->C : Response
int size = readVarInt(input);
int packetId = readVarInt(input);
if (packetId == -1) {
throw new IOException("Premature end of stream.");
}
if (packetId != 0x00) { //we want a status response
throw new IOException("Invalid packetID");
}
int length = readVarInt(input); //length of json string
if (length == -1) {
throw new IOException("Premature end of stream.");
}
if (length == 0) {
throw new IOException("Invalid string length.");
}
byte[] in = new byte[length];
input.readFully(in); //read json string
String json = new String(in);
// C->S : Ping
long now = System.currentTimeMillis();
output.writeByte(0x09); //size of packet
output.writeByte(0x01); //0x01 for ping
output.writeLong(now); //time!?
// S->C : Pong
readVarInt(input);
packetId = readVarInt(input);
if (packetId == -1) {
throw new IOException("Premature end of stream.");
}
if (packetId != 0x01) {
throw new IOException("Invalid packetID");
}
long pingtime = input.readLong(); //read response
// print out server info
System.out.println(json);
System.out.println("Done!");
}
public static byte [] createHandshakeMessage(String host, int port) throws IOException {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
DataOutputStream handshake = new DataOutputStream(buffer);
handshake.writeByte(0x00); //packet id for handshake
writeVarInt(handshake, 4); //protocol version
writeString(handshake, host, StandardCharsets.UTF_8);
handshake.writeShort(port); //port
writeVarInt(handshake, 1); //state (1 for handshake)
return buffer.toByteArray();
}
public static void writeString(DataOutputStream out, String string, Charset charset) throws IOException {
byte [] bytes = string.getBytes(charset);
writeVarInt(out, bytes.length);
out.write(bytes);
}
public static void writeVarInt(DataOutputStream out, int paramInt) throws IOException {
while (true) {
if ((paramInt & 0xFFFFFF80) == 0) {
out.writeByte(paramInt);
return;
}
out.writeByte(paramInt & 0x7F | 0x80);
paramInt >>>= 7;
}
}
public static int readVarInt(DataInputStream in) throws IOException {
int i = 0;
int j = 0;
while (true) {
int k = in.readByte();
i |= (k & 0x7F) << j++ * 7;
if (j > 5) throw new RuntimeException("VarInt too big");
if ((k & 0x80) != 128) break;
}
return i;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With