Skip to content

Instantly share code, notes, and snippets.

@ewized ewized/statusping.py
Last active Mar 9, 2019

Embed
What would you like to do?
Python3 class to ping a Minecraft server and get its response including ping in ms
#!/usr/bin/python3
import socket
import struct
import json
import time
class StatusPing:
""" Get the ping status for the Minecraft server """
def __init__(self, host='localhost', port=25565, timeout=5):
""" Init the hostname and the port """
self._host = host
self._port = port
self._timeout = timeout
def _unpack_varint(self, sock):
""" Unpack the varint """
data = 0
for i in range(5):
ordinal = sock.recv(1)
if len(ordinal) == 0:
break
byte = ord(ordinal)
data |= (byte & 0x7F) << 7*i
if not byte & 0x80:
break
return data
def _pack_varint(self, data):
""" Pack the var int """
ordinal = b''
while True:
byte = data & 0x7F
data >>= 7
ordinal += struct.pack('B', byte | (0x80 if data > 0 else 0))
if data == 0:
break
return ordinal
def _pack_data(self, data):
""" Page the data """
if type(data) is str:
data = data.encode('utf8')
return self._pack_varint(len(data)) + data
elif type(data) is int:
return struct.pack('H', data)
elif type(data) is float:
return struct.pack('L', int(data))
else:
return data
def _send_data(self, connection, *args):
""" Send the data on the connection """
data = b''
for arg in args:
data += self._pack_data(arg)
connection.send(self._pack_varint(len(data)) + data)
def _read_fully(self, connection, extra_varint=False):
""" Read the connection and return the bytes """
packet_length = self._unpack_varint(connection)
packet_id = self._unpack_varint(connection)
byte = b''
if extra_varint:
# Packet contained netty header offset for this
if packet_id > packet_length:
self._unpack_varint(connection)
extra_length = self._unpack_varint(connection)
while len(byte) < extra_length:
byte += connection.recv(extra_length)
else:
byte = connection.recv(packet_length)
return byte
def get_status(self):
""" Get the status response """
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as connection:
connection.settimeout(self._timeout)
connection.connect((self._host, self._port))
# Send handshake + status request
self._send_data(connection, b'\x00\x00', self._host, self._port, b'\x01')
self._send_data(connection, b'\x00')
# Read response, offset for string length
data = self._read_fully(connection, extra_varint=True)
# Send and read unix time
self._send_data(connection, b'\x01', time.time() * 1000)
unix = self._read_fully(connection)
# Load json and return
response = json.loads(data.decode('utf8'))
response['ping'] = int(time.time() * 1000) - struct.unpack('L', unix)[0]
return response
@hookbin

This comment has been minimized.

Copy link

hookbin commented Mar 20, 2018

Traceback (most recent call last):
File "\StatusPing.py", line 104, in get_status
self._send_data(connection, b'\x01', time.time() * 1000)
File "
\StatusPing.py", line 65, in _send_data
data += self._pack_data(arg)
File "***\StatusPing.py", line 56, in _pack_data
return struct.pack('i', int(data))
struct.error: argument out of range

@MarshalX

This comment has been minimized.

Copy link

MarshalX commented Aug 5, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.