Sockets - UDP Pakete senden

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
think
User
Beiträge: 37
Registriert: Donnerstag 22. Februar 2007, 10:02
Wohnort: Schweiz

Hallo miteinander,

Ich versuche grad dabei, einzelne Pakete auf den Weg zu schicken. Als Ausganglage dafür nehme ich folgenden Code:

Code: Alles auswählen

# Client program

from socket import *

# Set the socket parameters
host = "localhost"
port = 21567
buf = 1024
addr = (host,port)

# Create socket
UDPSock = socket(AF_INET,SOCK_DGRAM)

def_msg = "===Enter message to send to server===";
print "\n",def_msg

# Send messages
while (1):
	data = raw_input('>> ')
	if not data:
		break
	else:
		if(UDPSock.sendto(data,addr)):
			print "Sending message '",data,"'....."

# Close socket
UDPSock.close()
Die erwarteten Daten entsprechen folgendem Muster:

Code: Alles auswählen

©255255255- RCon -
RCon stands for "Remote Control". It allows you to control dedicated servers.

©255255255- Server Setup -
Before you can use remote control you have to set an rcon password.
©255000000Servers without rcon password cannot be remotely controlled!
To set an rcon password you can use the server menu or the command "sv_rcon" followed by the password.

©255255255- Using RCon as Client -
After setting the rcon password you have to do the following:
- Join your server
- open the console
- type: rcon_password YOURPW
- type: rcon YOURCOMMANDS
You have to replace "YOURPW" with the rcon password you set before.
"YOURCOMMANDS" has to be replaced with one or more commands
you want to execute on your server.

Please note: You only have to use "rcon_password" ONE time after joining the server!
 Afterwards you can use "rcon" as often as you like.

©255255255- Using external RCon -
It is also possible to use RCon without joining the server.
You either need an application which does this or you have to write your own one.
This is what you have to send by UDP:
1 Byte: 0
1 Byte: 0
1 Byte: 242
1 Byte: length of password string (X)
X Bytes: password string, each char one byte
2 Bytes (unsigned short): length of command string (X)
X Bytes: command string, each char one byte

"password string" has to contain the rcon password and "command string" the command(s) you want to execute.

©255000000Warning: External Rcon is a security risk. Password and commands are not encrypted.
The transmission is not reliable because plain UDP is used.

»Return«
Nun stellt sich die Frage, wie ich dies richig mitgebe. Habe schon mit allerlei Kombinationen und Möglichkeiten rumgespielt. Hexdump, etc.

Kann mir wer auf die Sprünge helfen?
Zuletzt geändert von think am Dienstag 17. März 2009, 10:16, insgesamt 1-mal geändert.
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Wirf einen Blick ins Modul "struct" (aus der Standard Library):

Code: Alles auswählen

import struct
rcon_template = "!B%usH%us"
password="geheim"
befehl = "BEFEHL"
rcon_packet = "\x00\x00\xF2" + struct.pack(rcon_template % (len(password), len(befehl)),
                          len(password),
                          password,
                          len(befehl),
                          befehl,
			  )
:twisted:
hth, Jörg
erst-posten-dann-testen-Fehler korrigiert
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
Benutzeravatar
think
User
Beiträge: 37
Registriert: Donnerstag 22. Februar 2007, 10:02
Wohnort: Schweiz

Vielen dank, hilft mir schon mal ungemein.


Die Dokumentation, die ich gefunden habe, war anscheinend falsch. Ich habe die Pakete mal aufgezeichnet und aufgeschlüsselt:

Code: Alles auswählen

0000   01 00 f2 0a 65 72 73 74 65 72 74 65 73 74 0f 00  ....erstertest..
0010   73 61 79 20 68 65 6c 6c 6f 20 77 6f 72 6c 64     say hello world

0000   01 00 f2 0b 7a 77 65 69 74 65 72 74 65 73 74 0c  ....zweitertest.
0010   00 73 61 79 20 73 6e 6f 77 62 61 6c 6c           .say snowball

erstertest = 65 72 73 74 65 72 74 65  73 74 
zweitertest = 7A 77 65 69 74 65 72 74  65 73 74

say hello world = 73 61 79 20 68 65 6C 6C 6F 20 77 6F 72 6C 64
say snowball = 73 61 79 20 73 6E 6F 77 62 61 6C 6C
Heisst also einfach, dass es erst 01 anstelle von 00 heissen muss. Das ist leicht geändert. Aber nach der Länge des Passworts, also z.B. nach 0f (f=15 = say hello world) muss nochmal 00 hin. Ich muss den String meiner Meinung nach also nochmal splitten oder das rcon_template ändern. Habe nun mit Hilfe von http://docs.python.org/library/struct.html einiges probiert, komme aber nicht wirklich auf einen grünen Ast.

Gehen meine Überlegungen völlig in die falsche Richtung oder krieg ich einfach nicht die richtige Kombination zusammen?
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Kannst du verraten, worum es hier überhaupt geht ? :)
(Gugel findet mit "rcon" lauter Spiele-server-gedöns, der sich aber je nach Spiel unterscheidet).
Die 0 nach dem 0x0F (=15, die Länge von "say hello world") lässt sich mit der Bytereihenfolge erklären -> Probier mal:

Code: Alles auswählen

#Alt: Network-byteorder (=big-endian)
# rcon_template = "!B%usH%us"
#neu: little-endian (x86-Reihenfolge)
rcon_template = "<B%usH%us"
hth, Jörg
Wir haben schon 10% vom 21. Jahrhundert hinter uns!
Benutzeravatar
think
User
Beiträge: 37
Registriert: Donnerstag 22. Februar 2007, 10:02
Wohnort: Schweiz

Es geht auch um so ein Gedöns. RCON steht einfach für Remote Connection und erlaubt die Fernsteuerung des Servers. Benutzen viele Spiele. Unter anderem Quake 3D, etc.

Deine Lösung funktioniert übrigens. Herzlichen Dank.

Mein Problem ist nur, das er jetzt jedes mal nach Ausführung des Befehls einen Beep von sich gibt. Kann man das unterbinden? Das ganze läuft unter Windows mit folgendem Code:

Code: Alles auswählen

# Client program
import struct
from socket import *

# Set the socket parameters
host = "localhost"
port = 21567
buf = 1024
addr = (host,port)

# Create socket
UDPSock = socket(AF_INET,SOCK_DGRAM)

def_msg = "===Enter message to send to server===";
print "\n",def_msg

# Send messages
while (1):
	rcon_password = raw_input('rcon pass >> ')
	rcon_command = raw_input('rcon command >> ')
	
	if not rcon_password and rcon_command:
		break
	else:
		rcon_template = "<B%usH%us"
		rcon_packet = "\x01\x00\xF2" + struct.pack(rcon_template % (len(rcon_password), len(rcon_command)),
			len(rcon_password),
			rcon_password,
			len(rcon_command),
			rcon_command,
		)
				
		if(UDPSock.sendto(rcon_packet,addr)):
			print "Sending message '",rcon_packet

# Close socket
UDPSock.close()
Benutzeravatar
b.esser-wisser
User
Beiträge: 272
Registriert: Freitag 20. Februar 2009, 14:21
Wohnort: Bundeshauptstadt B.

Mein Problem ist nur, das er jetzt jedes mal nach Ausführung des Befehls einen Beep von sich gibt
Dann gibst du irgendwo ein "\a" (="\x07", 7...) aus ;)
Vermutlich da: "print "Sending message '",rcon_packet" (Z. 34 in deinem Post).
Warum "print"-est du das Binär-Paket überhaupt (noch)?
Benutzeravatar
think
User
Beiträge: 37
Registriert: Donnerstag 22. Februar 2007, 10:02
Wohnort: Schweiz

Eigentlich nur zu "Debugging Zwecken". Viel gebracht hats ja wie man sieht nicht. :wink: Schlussendlich fliegts eh raus.
BlackJack

Zur Fehlersuche solltest Du solche Binärdaten besser mit `repr()` formatieren, damit nichts piept und man genau sieht was da enthalten ist.

Code: Alles auswählen

print "Sending message:", repr(rcon_packet)
Benutzeravatar
think
User
Beiträge: 37
Registriert: Donnerstag 22. Februar 2007, 10:02
Wohnort: Schweiz

Danke, so eine Ausgabe hatte ich mir in etwa erhofft. :)
Antworten