Singleplayer with other friends
SirLennox
2023-10-31 04:06:15תיאור
Opening a peer to peer session to other friends over uPnP is blocked by many routing softwares and might cause errors. This also occurs if I try to open a session with one of my friends, who has uPnP disabled in his router config. Holepunching would be more effective than uPnP because it can't be blocked by routers. <- I didn't look over it if it is uPnP, so correct me if I am wrong - but still - it doesn't really work so this explaination might help you
Some technical information about Holepunching:
Required: 2 clients, 1 gateway server
How does it work?
You just simply open a connection from each client to the gateway server. Make sure to enable SO_REUSEADDR for both clients. After both clients are connected, the server exchanges the public ip addresses and public ports of the incoming connection with the opposing client, so the first client knows ip and port of the second client and the second client knows ip and port of the first client. At this point, both connections can be closed. Before doing so, you should save the local address of the socket on the client side. After the sockets are closed, both clients create a socket and bind them to the local address of the previous socket and connect to the public ip and port of the opposing client. Now both clients are connected with each other through the hole in the router firewall.
Just some pseudo code to understand it better [Java IO is outdated, please use Java NIO]:
Client:
socket = new Socket();
socket.setReuseAddress(true);
socket.connect(gateway);
input = new DataInputStream(socket.getInputStream());
while (input.available() <= 0) { } // wait
otherAddressBytes = new byte[input.read()]; /* 4 bytes = ipv4, 16 bytes = ipv6 - Note: Many people don't have IPv6 support, maybe put the server IPv4 only to prevent connection failure and fix the size on 4 bytes */
input.read(otherAddressBytes);
localAddress = socket.getLocalAddress();
otherAddress = InetAddress.getByAddress(otherAddress);
port = input.readUnsignedShort(); // port range: 0-65535 (unsigned short max value)
socket.close();
socket = new Socket();
socket.setReuseAddress(true);
socket.bind(localAddress);
socket.connect(new InetSocketAddress(otherAddress, port));
/* Peer to peer connection established */
Server:
server = new ServerSocket(port);
client1 = server.accept();
client2 = server.accept();
/* Sends InetAddress#getAddress as bytes and the port as unsigned short */
sendAddress(client1, client2.getRemoteAddress());
sendAddress(client2, client1.getRemoteAddress());
I hope this might save you some time, as I tried to build this in without any pre-knowledge it took me way too long :)
Operating System: Windows 10
LabyMod Version: 4.1.3
Minecraft Version: 1.18.2
תגובות
-
SirLennox
2023-10-31 04:21:51Important side note: Public and local ports aren't the same, but mapped to each other, that means the local port of your socket is mapped to the public port of your socket, so you have to bind your socket on the local port to make it available on the public port.