"Connection reset" gbxRemote Socket

M

Marco01_809

Gast
Hi Java-Forum,

es gibt ein bekanntes Rennspiel namens "Trackmania". Natürlich gibt es auch einen Online-Modus und dafür kann man sich "Tm Dedicated Server" einrichten. Diese sind aber langweilig, denn man kann nur fahren, keine Rekorde, etc.
Dazu hat der TmServer eine "Schnittstelle" - XML-RPC. Das nennt sich "gbxRemote".
Über dieses gbxRemote lässt sich der Server sehr stark erweitern - dazu gehört auch das anzeigen von UI's Ingame etc.

Für PHP liegt ein gbxRemote-Client beim Server dabei. Es gibt auch schon um die 10 Projekte in PHP, doch mit PHP kommt man von der Leistung her recht schnell an die Grenze. -> Bei 100 Spielern auf einem Server kommen die UI's u.s.w. nicht mehr hinterher...

Ich versuche nun, das ganze in Java zu realisieren. Das wurde ebenfalls schonmal realisiert,
aber ich finde das vorhandene Tool nicht so toll, es bekam 2009 das letzte mal ein Update.

Es gibt sonst noch keine derartigen Tools in Java/C/C++/C#/Python/Perl was es eben nicht alles gibt.

Ich habe damit angefangen diese gbxRemote für Java zu programmieren.

Habe ein Problem mit meinem Source;
Die IXR_Client_Gbx, also die wichtigste Klasse die die Verbindung etc. verwaltet:
Java:
package gbxRemote;

/*
 * @package gbxRemote
 * @author Marco01_809
 * @copyright 2011
 * @version 1
 */

import java.io.Closeable;
import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;

public class IXR_Client_Gbx extends Socket implements Closeable {
	public final static byte VERSION = 1;

	public final static int DEFAULT_CONNECT_TIMEOUT = 15000;

	private byte GBXRemoteVersion;
	private InetSocketAddress addr;

	public IXR_Client_Gbx() {
		super();
	}

	public void connect(String host, int port, int timeout) throws IXR_Exception, UnknownHostException, IOException {
		addr = new InetSocketAddress(host, port);
		super.connect(addr, timeout);
		int length = getInputStream().read();
		if (length != 11)
			throw new IXR_Exception("Unknown lowlevel protocol with length: " + length, (short) -32300);
		getInputStream().skip(3);
		String protocolText = readString(length);
		String protocolType = protocolText.substring(0, 9);
		if (!protocolType.equals("GBXRemote"))
			throw new IXR_Exception("Unknown lowlevel protocol type: " + protocolType, (short) -32301);
		byte protocolVersion = Byte.parseByte(protocolText.substring(10));
		if (protocolVersion != 1 && protocolVersion != 2)
			throw new IXR_Exception("Unknown lowlevel protocol version: " + protocolVersion, (short) -32302);
		GBXRemoteVersion = protocolVersion;
	}

	public void connect(int port, int timeout) throws IXR_Exception, UnknownHostException, IOException {
		connect(InetAddress.getLocalHost().getHostName(), port, timeout);
	}

	public void connect(int port) throws IXR_Exception, UnknownHostException, IOException {
		connect(InetAddress.getLocalHost().getHostName(), port, DEFAULT_CONNECT_TIMEOUT);
	}

	public void connect(String host, int port) throws IXR_Exception, UnknownHostException, IOException {
		connect(host, port, DEFAULT_CONNECT_TIMEOUT);
	}

	@Override
	public void close() throws IOException {
		getOutputStream().flush();
		super.close();
		GBXRemoteVersion = 0;
	}

	public byte getGBXRemoteVersion() {
		return GBXRemoteVersion;
	}
	
	public InetSocketAddress getAddr() {
		return addr;
	}

	private String readString(int length) throws IOException {
		String text = "";
		for (int i = 0; i < length; i++)
			text += (char) getInputStream().read();
		return text;
	}

	private void writeString(String text) throws IOException {
		char[] chars = text.toCharArray();
		for (char c : chars)
			getOutputStream().write(c);
	}

	public void query(String method, String... args) throws IOException {
		String query = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><methodCall><methodName>" + method + "</methodName><params>";
		for (String a : args)
			query += "<param><value><int>" + System.currentTimeMillis() + "</int></value></param>"; // Nur provisorisch, natürlich sollen normalerweise die args mit dazugehörigem Datentypn übermittelt werden
		query += "</params></methodCall>";
		writeString(query);
		
		System.out.println(getInputStream().read()); // HIER TRITT DER FEHLER AUF!
	}
}

Meine IXR_Exception, die ich bei jedem Fehler freudig durch die Gegend werfe:
Java:
package gbxRemote;

/*
 * @package gbxRemote
 * @author Marco01_809
 * @copyright 2011
 * @version 1
 */

public class IXR_Exception extends Exception {
	public static final long serialVersionUID = 1;
	public final short code;
	
	public IXR_Exception(String message, short code) {
		super(message);
		this.code = code;
	}
	
	public short getCode() {
		return code;
	}
}

Und zu letzt meine Testklasse:
Java:
package jManiaServ;

import gbxRemote.IXR_Client_Gbx;
import gbxRemote.IXR_Exception;

import java.io.IOException;
import java.net.UnknownHostException;

public final class Main {

	private static IXR_Client_Gbx client;

	public static void main(String[] args) {
		try {
			long timebefore = System.currentTimeMillis();
			client = new IXR_Client_Gbx();
			client.connect(5004);
			long timeafter = System.currentTimeMillis();
			System.out.println((timeafter - timebefore) + " ms");
			System.out.println("GBXRemote Version: " + client.getGBXRemoteVersion());
			client.query("GetServerName");

		} catch (IXR_Exception e) {
			// Catch IXR Exceptions
			System.out.println("[IXR_Exception] " + e.getCode() + " \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(50);
		} catch (UnknownHostException e) {
			// Catch UnknownHostExceptions
			System.out.println("[UnknownHostException] \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(101);
		} catch (IOException e) {
			// Catch all other IOExceptions
			System.out.println("[IOException] \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(100);
		} catch (Exception e) {
			// Catch all other Exceptions
			System.out.println("[Exception] \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(2);
		}
	}
}
(Ich weiß, die ist nicht gerade schön mit den System.exit()'s aber die ist nur schnell zum Testen gedacht ;))

Dazu die Konsolenaudgabe:
Konsole hat gesagt.:
21 ms
GBXRemote Version: 2
[IOException] "Connection reset"! Execution aborted!
java.net.SocketException: Connection reset
at java.net.SocketInputStream.read(Unknown Source)
at java.net.SocketInputStream.read(Unknown Source)
at gbxRemote.IXR_Client_Gbx.query(IXR_Client_Gbx.java:93)
at jManiaServ.Main.main(Main.java:21)

Verbunden werde ich auf jedenfall, denn ich kann ja vom InputStream das Protokoll abfragen. (Natürlich läuft dazu der TmServer)

Hab die PHP-Beispiele mal angehängt;
basic.php = Anwendungsbeispiel der GbxRemote.*.php
GbxRemote.inc.php = Die besagte GbxRemote.
GbxRemote.bem.php = Dieselbe GbxRemote für Big Endian.
SpectatorUi.php und ListMethods.php = Weitere kleine Anwendungsbeispiele.

Bitte helft mir,
Gruß Marco.
 

Anhänge

  • PhpRemote.zip
    22,2 KB · Aufrufe: 0

thE_29

Top Contributor
Nunja, woher weiß der Server, wielange oder wann dein Query aufhört?
Maybe stimmt ja beim Query selbst schon was nicht..
 
M

Marco01_809

Gast
Vielen Dank für die Hilfe, das hier wäre die Funktion zum Senden einer Query in PHP:

IXR_Request->getXml() gibt z.B. folgendes zurück:
<?xml version=\"1.0\" encoding=\"utf-8\" ?><methodCall><methodName>GetServerName</methodName><params></params></methodCall>";

Java:
	protected function sendRequest(IXR_Request $request) {
		$xml = $request->getXml();

		@stream_set_timeout($this->socket, 20);  // timeout 20 s (to write the request)
		// send request
		$this->reqhandle++;
		if ($this->protocol == 1) {
			$bytes = pack('Va*', strlen($xml), $xml);
		} else {
			$bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml);
		}

		$bytes_to_write = strlen($bytes);
		while ($bytes_to_write > 0) {
			$r = fwrite($this->socket, $bytes);
			if ($r === false || $r == 0) {
				// connection interrupted
				return false; // or die?
			}

			$bytes_to_write -= $r;
			if ($bytes_to_write == 0)
				break;

			$bytes = substr($bytes, $r);
		}

$this->reqhandle wurde im Konstruktor festgelegt, und wird auch nicht beim verbinden etc. verändert:

Java:
	function IXR_Client_Gbx() {
		$this->socket = false;
		$this->reqhandle = 0x80000000;
	}

"$bytes = pack('VVa*', strlen($xml), $this->reqhandle, $xml);"
Ich sehe gerade das es auch die Länge und den "reqhandle" mit zum senden in $bytes packt.
Hab dann ebenfalls ein reqhandle implementiert und bei der query() erhöht:
Java:
	public void query(String method, String... args) throws IOException {
		String query = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><methodCall><methodName>" + method + "</methodName><params>";
		for (String a : args)
			query += "<param><value><int>" + System.currentTimeMillis() + "</int></value></param>" + (char) 10;

		query += "</params></methodCall>";
		reqhandle++;
		writeString(query.length() + reqhandle + query);

		System.out.println(isConnected()); // true
		System.out.println(getInputStream().read());  // HIER TRITT DIE EXCEPTION "Connection reset" AUF!
	}
Das ging ebenfalls nicht.
Was pack() macht: PHP: pack - Manual
Ich bin irgendwie zu blöd. ???:L Kann mir wieder jemand helfen?
 

thE_29

Top Contributor
Das pack ist sowas wie ein printf("FORMATOPTIONEN", params, param, ...); aus C bzw. ab Java 1.5 (oder 1.6) auch in System.out.printf

Dh, der baut Binärdaten (was wir eigentlich nicht brauchen, weil das Java macht) zusammen! Dh, wir müssen mal gucken was der da so reinpackt!

Die Frage ist halt, welches Protokoll du nutzt!
Ist es Version 1 = formater Va* und wenn nicht 1 = VVa*.

Va* =
V steht für vorzeichenloser Long-Typ (immer 32 Bit, Byte-Folge Little Endian).
Dh, du musst schonmal 4 Bytes für die Länge benutzen!
und das a steht für Hexnull gefüllte Zeichenkette (der * heißt eigentlich, den Rest unformatiert rein).
Bei Version nicht 1 gehört noch der ReqHandle hin, aber auch mit 4 Bytes!

Dh, dein Problem ist, dass du die Zahlen als String schickst und diese auch nur 1 Byte lang sind (bzw. sobreit der String halt ist) und du keine Hexnull gefüllte Zeichenkette hast!


Ich würde mal so probieren

In deiner Zeile 8, änder writeString auf das hier:
Code:
writeString(getByteFromNumber(len, true) + getByteFromNumber(reqHandle, true) +query + '\0');

Dann bau noch die Methode getByteFromNumber ein

Code:
public static String getByteFromNumber(int len, boolean order)
	{
		StringBuffer strBuf = new StringBuffer();
		strBuf.append((char)(len & 255));
		len = len >> 8;
		strBuf.append((char)(len & 255));
		len = len >> 8;
		strBuf.append((char)(len & 255));
		len = len >> 8;
		strBuf.append((char)(len & 255));
		if(order)
		{
			strBuf = strBuf.reverse();
		}
		return strBuf.toString();
	}

Order gibt Little und Big Endian an. Da du aber beim Einlesen nur den ersten Byte ausgewertet hast und die restlichen 3 geskippt hast, sollte das mit true hoffentlich passen! Ansonsten mal getByteFromNumber mit false aufrufen!

Bin erst wieder morgen da, also teste mal obs klappt!
 
Zuletzt bearbeitet:
M

Marco01_809

Gast
Woow, vielen Dank. Darauf wäre ich natürlich nie selber gekommen.
Mit order = true hat es nicht geklappt aber mit order = false
292.gif


Hatte mir die pack() funktion von PHP schon angesehen, aber die hat mich einfach nur verwirrt...
Ist VVa* also eine Reihenfolge? Der erste Buchstaben "V" bezieht sich auf den 1. Parameter, das 2. "V" auf den 2., und das "a" auf den 3?
Das würde für mich wenigstens dann auch sinn machen, weil beim Protokoll v2 der reqhandle-Parameter mitgesendet wird. (Wozu auch immer der Server den braucht :D)

Die Erweiterung zu dem Spiel, Trackmania, ist Trackmania Forever. Und ich glaube, das der Server seit "Forever" immer das Protokoll 2 benutzt. Ich probiere das ganze an einem Forever-Server aus, also "GBXRemote 2"

Wozu muss das ganze denn 4 Bytes lang sein? o_O
Die ersten 4 Bytes vom Server sind ja "11 0 0 0". Da erst danach der 11-Zeichen lange String kam, hab ich die anderen 3 einfach geskippt. (Gott, bis ich alleine das rausgefunden hatte :lol:)

Kannst du mir eben noch erklären, was eine Hexnull gefüllte Zeichenkette ist und was deine Funktion macht?

EDIT: Ich bekomme als Antwort auf
method: "Authenticate"
param1(String): "SuperAdmin"
param2(String): "-MeinPasswort-"

folgendes:
"150 0 0 0 1 0 0
?<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param><value><boolean>1</boolean></value></param>
</params>
</methodResponse>"
Vielen Dank! :)
 
Zuletzt bearbeitet von einem Moderator:

thE_29

Top Contributor
Also VVa* sind Formatierungsparameter!

Dh, der erste Parameter ist ein V, der 2te auch und der 3te ist ein Hexnull String.
In C wird ein String immer mit Hexnull beendet.

Und in der PHP Doku steht zu V halt:
V vorzeichenloser Long-Typ (immer 32 Bit, Byte-Folge Little Endian)
32bit = 4bytes
und bei a:
a mit NUL gefüllte Zeichenkette
Damit ist gemeint, ein String mit Hexnull aufhört. Also mit \0 aufhören.

Und zu den 4 Bytes was du ausliest. Sobald da mal ein String daherkommt der länger als 256 Zeichen ist, dann wirst du ein Problem mit deiner "Methode" haben.
Weil dann wäre zB am ersten Byte die 255 und im 2ten Byte wäre eine 1 und die müsstest "zusammenzählen" (eher Byte verschieben und logisch verknüpfen), damit du auf die richtige Länge kommst.

Wenn du nicht weißt wie du die Bytes richtig ausrechnen kannst, dann melde dich, dann kann ichs dir zeigen ;)
 
M

Marco01_809

Gast
Dh, der erste Parameter ist ein V, der 2te auch und der 3te ist ein Hexnull String.
In C wird ein String immer mit Hexnull beendet.
Genau das meinte ich, danke ;)

Und zu den 4 Bytes was du ausliest. Sobald da mal ein String daherkommt der länger als 256 Zeichen ist, dann wirst du ein Problem mit deiner "Methode" haben.
Weil dann wäre zB am ersten Byte die 255 und im 2ten Byte wäre eine 1 und die müsstest "zusammenzählen" (eher Byte verschieben und logisch verknüpfen), damit du auf die richtige Länge kommst.
Warte, das heißt das Maximum wäre 1020 Zeichen? Sicherlich doch nicht oder?
Es ist doch ein 32-bit Long, also 9223372036854775807? (Mal davon abgesehen das das 8 GB sind...)
EDIT: Nein, es wäre dann doch die Maximale Größe eines usigned int?

Wenn du nicht weißt wie du die Bytes richtig ausrechnen kannst, dann melde dich, dann kann ichs dir zeigen ;)
Weiß ich nicht :D
Wäre wirklich nett wenn du's mir zeigst :)

BTW: Hier ist mal mein aktueller Source:
Gbx_Exception:
Java:
package gbxRemote;

/*
 * @package gbxRemote
 * @author Marco01_809
 * @copyright 2011
 * @version 1
 */

public class Gbx_Exception extends Exception {
	public static final long serialVersionUID = 1;

	private final short code;
	private final boolean serverFault;

	public Gbx_Exception(String message, short code, boolean serverFault) {
		super(message);
		this.code = code;
		this.serverFault = serverFault;
	}

	public short getCode() {
		return code;
	}

	public boolean getServerFault() {
		return serverFault;
	}
}
Gbx_Client:
Java:
package gbxRemote;

/*
 * @package gbxRemote
 * @author Marco01_809
 * @copyright 2011
 * @version 1
 */

import java.io.Closeable;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.nio.ByteOrder;

public class Gbx_Client extends Socket implements Closeable {
	public final static long serialVersionUID = 1L;

	public final static int DEFAULT_CONNECT_TIMEOUT = 8000;
	public final static int DEFAULT_PORT = 5000; // 0 - 65535
	public final static String DEFAULT_HOST = "localhost";
	// TODO: static { try { DEFAULT_HOST = InetAddress.getLocalHost().getHostName(); } catch (UnknownHostException ex) { DEFAULT_HOST = "localhost"; } }

	public final static byte LENGTH_BYTES = 4;

	public final static boolean BIG_ENDIAN;
	static {
		if (ByteOrder.nativeOrder().toString() == "BIG_ENDIAN")
			BIG_ENDIAN = true;
		else
			BIG_ENDIAN = false;
	}

	private long maxRequestSize = 524288; // 512 KB
	private long maxReceiveSize = 4194304; // 4 MB

	private byte gbxRemoteVersion;
	private InetSocketAddress addr;
	private int reqHandle = 0x80000000;

	public Gbx_Client() {
		super();
		setAddr();
	}

	public void connect(int timeout) throws Gbx_Exception, UnknownHostException, IOException {
		super.connect(addr, timeout);
		long length = getNumberFromStream();
		if (length != 11)
			throw new Gbx_Exception("Unknown lowlevel protocol with length: " + length, (short) -32300, false);
		String protocolText = readString(length);
		String protocolType = protocolText.substring(0, 9);
		if (!protocolType.equals("GBXRemote"))
			throw new Gbx_Exception("Unknown lowlevel protocol type: " + protocolType, (short) -32301, false);
		byte protocolVersion = Byte.parseByte(protocolText.substring(10));
		if (protocolVersion != 1 && protocolVersion != 2)
			throw new Gbx_Exception("Unknown lowlevel protocol version: " + protocolVersion, (short) -32302, false);
		gbxRemoteVersion = protocolVersion;
	}

	public void connect() throws Gbx_Exception, UnknownHostException, IOException {
		connect(DEFAULT_CONNECT_TIMEOUT);
	}

	public void setAddr() {
		addr = new InetSocketAddress(DEFAULT_HOST, DEFAULT_PORT);
	}

	public void setAddr(int port) {
		addr = new InetSocketAddress(DEFAULT_HOST, port);
	}

	public void setAddr(String host, int port) {
		addr = new InetSocketAddress(host, port);
	}

	public void setAddr(InetSocketAddress addr) { // SocketAddress ?
		this.addr = addr;
	}

	public InetSocketAddress getAddr() {
		return addr;
	}

	public byte getGbxRemoteVersion() {
		return gbxRemoteVersion;
	}

	public void setMaxRequestSize(long maxRequestSize) {
		this.maxRequestSize = maxRequestSize;
	}

	public long getMaxRequestSize() {
		return maxRequestSize;
	}

	public void setMaxReceiveSize(long maxReceiveSize) {
		this.maxReceiveSize = maxReceiveSize;
	}

	public long getMaxReceiveSize() {
		return maxReceiveSize;
	}

	@Override
	public void close() throws IOException {
		getOutputStream().flush();
		super.close();
		gbxRemoteVersion = 0;
		reqHandle = 0x80000000;
	}

	// ################################################ //

	private String readString(long length) throws IOException {
		String text = "";
		for (int i = 0; i < length; i++)
			text += (char) getInputStream().read();
		return text;
	}

	private void writeString(String text) throws IOException {
		char[] chars = text.toCharArray();
		for (char c : chars)
			getOutputStream().write(c);
	}

	private static String getBytesFromNumber(long num) {
		StringBuffer str = new StringBuffer();
		for (byte i = 0; i < LENGTH_BYTES; i++) {
			str.append((char) (num & 255));
			num = num >> 8;
		}
		if (BIG_ENDIAN)
			str = str.reverse();
		return str.toString();
	}

	// TODO: Das kann so ja nicht stimmen:
	private static long getNumberFromBytes(String str) {
		char[] chars = str.toCharArray();
		if (BIG_ENDIAN)
			return chars[chars.length - 1];
		else
			return chars[0];
	}

	private long getNumberFromStream() throws IOException {
		return getNumberFromBytes(readString(LENGTH_BYTES));
	}

	// ################################################ //

	public void query(String method, String... args) throws Gbx_Exception, IOException {
		// Build request
		String query = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><methodCall><methodName>" + method + "</methodName><params>";
		for (String a : args)
			query += "<param><value><string>" + a + "</string></value></param>\n";
		query += "</params></methodCall>";
		reqHandle++;
		if (gbxRemoteVersion == 1)
			query = getBytesFromNumber(query.length()) + query + "\0";
		else if (gbxRemoteVersion == 2)
			query = getBytesFromNumber(query.length()) + getBytesFromNumber(reqHandle) + query + "\0";

		// Send request
		if (query.length() > maxRequestSize)
			throw new Gbx_Exception("Request too big: " + query.length(), (short) -32700, false);
		writeString(query);

		// Get result
		long length = getNumberFromStream();
		System.out.println("Länge des Strings: " + length);
		for (int i = 0; i < 4; i++)
			System.out.print(getInputStream().read() + " ");
		System.out.println("\r\n" + readString(length));
	}
}
Testklasse:
Java:
package jManiaServ;

import gbxRemote.Gbx_Client;
import gbxRemote.Gbx_Exception;

import java.io.IOException;
import java.net.UnknownHostException;

public final class Main {

	private static Gbx_Client client;

	public static void main(String[] args) {
		try {
			client = new Gbx_Client();
			
			client.setAddr(5004);
			
			client.setKeepAlive(true);
			client.setTcpNoDelay(true);

			System.out.println("Big Endian: " + Gbx_Client.BIG_ENDIAN);

			long timebefore = System.currentTimeMillis();
			
			client.connect();
			
			long timeafter = System.currentTimeMillis();
			System.out.println((timeafter - timebefore) + " ms");
			
			System.out.println("GBXRemote Version: " + client.getGbxRemoteVersion());
			
			client.query("Authenticate", "SuperAdmin", "-Password entfernt-");

		} catch (Gbx_Exception e) {
			// Catch Gbx_Exceptions
			System.out.println("[Gbx_Exception] " + e.getCode() + " \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(50);
		} catch (UnknownHostException e) {
			// Catch UnknownHostExceptions
			System.out.println("[UnknownHostException] \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(101);
		} catch (IOException e) {
			// Catch all other IOExceptions
			System.out.println("[IOException] \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(100);
		} catch (Exception e) {
			// Catch all other Exceptions
			System.out.println("[Exception] \"" + e.getLocalizedMessage() + "\"! Execution aborted!");
			e.printStackTrace();
			System.exit(2);
		}
	}
}
Konsolenausgabe:
Konsole hat gesagt.:
Big Endian: false
7 ms
GBXRemote Version: 2
Länge des Strings: 150
1 0 0 128
<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
<params>
<param><value><boolean>1</boolean></value></param>
</params>
</methodResponse>
Werde mich jetzt mal mit der PHP Funktion zum Holen eines Ergebnisses befassen :)
 
Zuletzt bearbeitet von einem Moderator:

thE_29

Top Contributor
Also bei 4 Bytes wäre der maximale Wert der hier: 4.294.967.295 (weil es unsigned ist)

Man muss wenn man "Zahlen" über einen Stream schickt, aufhören an einen String zu denken! In einen Byte bekommt man maximal 255 rein. Nur sind 2 Bytes mit jeweils 255 eben nicht 510 sondern 65535.

Da ich zZ nix zum Austesten habe, würde ich das so implementieren.

Code:
public long getNumberFromString(String data)
{
    byte [] bytes = data.getBytes();
    long ret = 0;
    if(BIG_ENDIAN)
    {
       for(int x = 0; x != bytes.length; x++)
       {
          ret = ret << 8;
          ret = ret | (char)(bytes[x]);
      }
    }
    else
    {
       for(int x = bytes.length - 1; x >= 0; x--)
       {
          ret = ret << 8;
          ret = ret | (char)bytes[x];
       }
    }
    return ret;
  }

Hier übergibst du den String. Bei dir wären das halt die ersten 4 Bytes die die Länge angeben.
Dh, wenn du einen String zurückbekommst, der 300 lang wäre, würden deine ersten 4 bytes so aussehen:
44 1 0 0

Die Methode arbeitet bei Little Endian von hinten nach vorne.
Dh, beim ersten Durchlauf schiebt es den Wert 0 um 8 bits nach links (bleibt bei 0), dann wird es mit einer logischen Operation ( oder = | ) verknüpft. 0 | 0 = 0.
2ter Durchlauf ist in dem Bsp das gleiche (weil Wert 0).
Beim 3ten Durchlauf (der for Schleife in der Methode halt), wird es schon interessant.
Der Bytewert ist 1 und 0 | 1 = 1.
Dann beim 4ten Durchlauf wird der Wert um 8 bits nach links geshifted. Dh, das ist dann nicht mehr 1 sondern 256 (weil am 9ten Bit ein 1er ist).
Weiter im 4ten Durchlauf wird die Zahl mit oder verknüpft. Dh, 256 | 44 = 300 und genau das wäre das richtige Ergebnis.

Du müsstest halt die Bitmasken betrachten! Also
256 = 0000 0001 0000 0000
044 = 0000 0000 0010 1100
das mit logisch Oder verknüpft = überall wo ein 1er ist kommt ein 1er hin!
300 = 0000 0001 0010 1100

Und so kommt man auf die Zahl.

Die andere Methode die ich dir geschrieben habe macht das halt in die andere Richtung ;)
Also es nimmt die Zahl und wandelt es in eine Bitmaske um! Thats the trick...
 
M

Marco01_809

Gast
Java:
	private static long getNumberFromBytes(String str) {
		char[] chars = str.toCharArray();
		long num = 0;
		if (BIG_ENDIAN)
			for (int x = 0; x != chars.length; x++)
				num = (num << 8) | chars[x];
		else
			for (int x = chars.length - 1; x >= 0; x--)
				num = (num << 8) | chars[x];
		return num;
	}
So funktioniert das ganze. Du hattest es mit Bytes gemacht. aber Bytes haben doch nur -128 bis 127 statt der benötigten 0 - 255. Von daher kann das doch nicht gehen? Daher gab mir deine Funktion "63" anstatt von (richtigen) "150" zurück. Mit chars funktioniert es jetzt.
Finde es auch wirklich Sch... ade das Java keine Unsigned Datentypen hat, was ja die Netzwerk/Datei-Programmierung doch erschwert.

Muss mich nochmal seehr bedanken! :) Hast mir wirklich sehr nett geholfen :)
 
Zuletzt bearbeitet von einem Moderator:

thE_29

Top Contributor
Najo, byte gibt es dir als diese Zahl aus, aber die Bitmaske ist ja die gleiche ;)

Dh, es hatte anders genauso klappen sollen..
Aber Hauptsache es geht jetzt ;)
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
X Connection reset, wieso? Java Basics - Anfänger-Themen 4
Hallolu PONG Parent-Child connection Java Basics - Anfänger-Themen 3
B MySQL (jdbc) -> connection liefert NULL Java Basics - Anfänger-Themen 3
G sql server connection mit windows authentication Java Basics - Anfänger-Themen 2
P java.net.ConnectException: Connection refused: connect Java Basics - Anfänger-Themen 8
S Input/Output URL Connection Problem Java Basics - Anfänger-Themen 5
H Connection Java Basics - Anfänger-Themen 9
B Prüfung auf erfolgreiche Connection? Java Basics - Anfänger-Themen 2
K Frage zu einer Connection in Java Java Basics - Anfänger-Themen 3
R JDK installieren Nach Update auf java 1.7 Connection refused Java Basics - Anfänger-Themen 9
M Netzwerkprogrammierung => Is connection alive? Java Basics - Anfänger-Themen 6
D Mysql Connection Close? Java Basics - Anfänger-Themen 14
B JDBC DB2 Connection Java Basics - Anfänger-Themen 1
D Facebook Connection problem Java Basics - Anfänger-Themen 2
M Audio Stream läuft auf :connection abort: socket write error Java Basics - Anfänger-Themen 2
G java.sql.Connection Connect ungleich null, aber geschlossen Java Basics - Anfänger-Themen 2
G JavaMail: Unrecognized SSL message, plaintext connection? Java Basics - Anfänger-Themen 3
G EJB - ConnectionPooling: Wie Connection erhalten? Java Basics - Anfänger-Themen 10
A Connection Prob Java Basics - Anfänger-Themen 3
S MySQL - connection Java Basics - Anfänger-Themen 8
J Kleine Connection Frage Java Basics - Anfänger-Themen 4
B java.net.ConnectException: Connection refused: connect ? Java Basics - Anfänger-Themen 2
T MySQL connection Java Basics - Anfänger-Themen 7
G db connection Java Basics - Anfänger-Themen 2
L Connection Pooling Grundlagenfragen Java Basics - Anfänger-Themen 2
K JDBC - Typ Connection in jeder Klasse neu öffnen? Java Basics - Anfänger-Themen 4
M Werte ändern sich nicht mehr nach Reset Java Basics - Anfänger-Themen 14
D .txt überschreiben mit BufferedWriter ohne reset Java Basics - Anfänger-Themen 6
L Level Reset funktioniert nicht Java Basics - Anfänger-Themen 3
L Java gui reset button Fehler!? Java Basics - Anfänger-Themen 2
L Java reset button Problem Java Basics - Anfänger-Themen 3
L Java reset button Problem Java Basics - Anfänger-Themen 9
L Variablen dekleration + reset Java Basics - Anfänger-Themen 16
F Reset in der switch Anweisung Java Basics - Anfänger-Themen 3
J Reset Button im Spiel Vier gewinnt einrichten Java Basics - Anfänger-Themen 8

Ähnliche Java Themen

Neue Themen


Oben