Socket Connection reset by peer nur per IP nicht über localhost

Zelnehlun

Mitglied
Hey,
Ich bin gerade eben auf ein, für mich, sehr seltsames Problem gestoßen. Ich versende mit meinem Server an den Client haufenweise Bytes. Der Client empfängt diese bis alle gesendet wurden.

Wenn ich den Client über "localhost" oder "127.0.0.1" verbinde läuft alles ohne Probleme ab.
Der Server verwendet den Port 8000, dieser ist freigeschalten und getestet.
Wenn ich über meine IP (die ich über Wie ist meine IP-Adresse? herausgefunden habe) auf den Server verbinde läuft die while Schlife für ~100 Runden und anschließend kommt es zu folgender Exception:

java.net.SocketException: Connection reset by peer: socket write error

Anscheinend schließt der Client den ObjectInputStream, dies passiert allerdings erst, nachdem der Server false gesendet hat. Durch herumprobieren habe ich herausgefunden, dass mein Server nie ein false schickt. Der Client wird also nicht durch meinen Programmtext geschlossen.

Hier noch der Quelltext:

Server:
Java:
while(audioInputStream.read(buffer, 0, buffer.length) != -1){
				out.writeBoolean(true); out.flush(); 
				out.write(buffer); out.flush();
			}

Client:
Java:
while(in.readBoolean()){
				if(j < 200000){
					in.read(buffer[j]);
				}else{
					in.read(tempBuffer);
				}
				
				j++;
			}

...

in.close();
s.close();

in ist mein ObjectInputStream und s mein Socket.

Ich bedanke mich schonmal jetzt für jede Hilfe.

*Edit*

Über Hamachi gibt es keine Probleme. Aber ich habe erneut getestet ob der Port freigeschalten ist, ja ist er.
 
Zuletzt bearbeitet:
Die IP die du bei "wieistmeineip" kriegst ist die IP von deinem Router/DSL Modem.

Für den Fall das du den Port nur Lokal auf deinem Rechner freigeschaltet hast:
Du musst in deiner Router Konfiguration auch einen sogenannten "Port Forwarding" Eintrag machen damit dieser die Daten an den richtigen Computer im LAN weiterleitet. Ansonsten weiß der Router ja nur den Port und nicht an welchen Rechner die Pakete den gehen sollen.
Portweiterleitung - Wikipedia

Ansonsten hilft die Sendeschleife mir nicht dein Problem so lösen. Poste mal die Segmente zur Adresse.
 
Von wie ist meine IP bekomme ich folgende Adresse:
95.88.164.168

Anscheinend ist die Größe die versendet werden darf begrenzt. Ich habe mir ausgeben lassen wie viel Bytes er empfängt, 2 mal empfängt er 1024 bytes, beim 3. mal nur noch 831 und anschließend die Exception.

Der Port ist auf dem Router freigeschalten über das Interface des Routers.

Was meinst du genau mit Segmente zur Adresse.

*Edit*

Der Client empfängt zuvor die Bestandteile für das Audio Format auch ohne Probleme:

Java:
float sampleRate = in.readFloat();
int sampleSizeInBits = in.readInt();
int channels = in.readInt();
boolean bigEndian = in.readBoolean();

In der Schleife werden wie gesagt 2 mal die richtige Anzahl (1024 bytes) gesendet und dann ~831 mit Exception. Wenn ich die "Pakete" verkleinere schafft er mehr Runden bis zur Exception. z.B. bei 512 bytes sendet er 4 mal 512 bytes, danach die Exception.
 
Zuletzt bearbeitet:
Damit meine ich, dass ich gerne sehen würde wo du deinen Socket erstellst, welche Konfiguration du vornimmst und wie/welche Adresse übergeben wird. Außerdem sind die verschiedenen Streams interessant.

Damit ich dein "Protokoll" richtig verstanden habe:
[float:sampleRate]
[int:sampleSizeInBits]
[int:channels]
[boolean:bigEndian]
[byte[]:audioData]

Außerdem habe ich so eine Idee woran es liegen könnte bzw. nen generelles Problem:
Du fütterst deinen Buffer mit Daten und nur wenn Daten geschrieben wurde versucht du welche zu senden. Was aber wenn du nur ne begrenze Menge aus Performence Gründen schicken kannst, der Buffer aber noch nicht leer ist? Bei localhost macht das keinen Unterschied aber übers Internet...
Nur so ne Idee... könnte theoretisch seien...

Dh. das müsste eher so aussehen:
while(!buffer.isEmpty()) {
// try sending data
}
 
Okay hier mehr Quelltext vor allem mit den Socket Zeilen:

Server:
Java:
public class Server {

	byte[] buffer = new byte[1024];
	static ServerSocket serverSocket;
	
	public static void main(String[] args){
		try{
			serverSocket = new ServerSocket(8000);
			
			while(true){
				new Server(serverSocket.accept());
			}
		}catch(Exception ex){
			System.out.println(ex);
			System.exit(0);
		}
	}
	
	Server(Socket s){
		try{
			File f = new File("audio.wav");
			AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(f);
			AudioFormat audioFormat = audioInputStream.getFormat();
			ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
			
			out.writeFloat(audioFormat.getSampleRate()); out.flush();
			out.writeInt(audioFormat.getSampleSizeInBits());  out.flush();
			out.writeInt(audioFormat.getChannels());  out.flush();
			out.writeBoolean(audioFormat.isBigEndian());  out.flush();
			
			while(audioInputStream.read(buffer, 0, buffer.length) != -1){
				out.writeBoolean(true); out.flush(); 
				out.write(buffer); out.flush();
			}
			
			out.writeBoolean(false); out.flush();
			
			out.close();
			s.close();
		}catch(Exception ex){
			System.out.println(ex);
		}
	}
}

Und hier der Client:
Java:
byte[][] buffer = new byte[200000][1024];
	byte[] tempBuffer = new byte[1024];
	AudioFormat audioFormat;
	SourceDataLine sourceDataLine;
	
	public static void main(String[] args){
		new Client();
	}
	
	Client(){
		try{
			String ip = JOptionPane.showInputDialog("IP Adresse");
			Socket s = new Socket(ip, 8000);
			ObjectInputStream in = new ObjectInputStream(s.getInputStream());
		
			float sampleRate = in.readFloat();
			int sampleSizeInBits = in.readInt();
			int channels = in.readInt();
			boolean bigEndian = in.readBoolean();
			
			audioFormat = new AudioFormat(sampleRate, sampleSizeInBits, channels, true, bigEndian);
			int j = 0;
			
			while(in.readBoolean()){
				if(j < 200000){
					System.out.println(in.read(buffer[j]));
				}else{
					in.read(tempBuffer);
				}
				
				j++;
			}

			in.close();
			s.close();
			
			DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class, audioFormat);
			sourceDataLine = (SourceDataLine)AudioSystem.getLine(dataLineInfo);
			
			new ClientThread().start();
		}catch(Exception ex){
			JOptionPane.showMessageDialog(null, ex.getMessage(), "Error", JOptionPane.ERROR_MESSAGE);
			System.exit(0);
		}
	}

Ich hoffe das ist noch einigermaßen übersichtlich, die Teile Interface und ähnliches habe ich rausgeschnitten. Das ganze ist natürlich sehr amateurhaft und dient mir mehr als Übung.

Der Buffer ist ein byte array mit 1024 Plätzen, er wird aus dem audioInputStream gelesen und gesendet. Beim Client soll er empfangen werden und ab damit in den Speicher.

Mit System.out.println(in.read(buffer[j])); lasse ich mir ausgeben wie viele Bytes tatsächlich empfangen wurden. Ein 1024 byte Paket wurde in allen meinen Tests empfangen, beim 2. oder 3. Paket waren es weniger.

Ich habe versucht im Server Pausen einzubauen durch Thread.sleep() variierend von 500ms bis 2 Sekunden. Kein Unterschied.

*Edit*

Nach weiterer Googelei bin ich darauf gestoßen, dass localhost natürlich Ports umgeht. D.h. das Problem muss an dem Router/Port liegen oder?
Wenn ich meinen PC über die cmd anpinge gibt es keine Datenverluste oder gravierende Schwankungen.
 
Auf anhieb finde ich den Fehler jetzt leider auch nicht. Mal geprüft was bei
String ip = JOptionPane.showInputDialog("IP Adresse");
rauskommt? einfach mal syso(ip)


Außerdem pack hier mal bei else auch ein system.out rein, dürfte eig noch nicht 20000 überschritten haben aber evtl ist irgendwo ein fehler und mach mal bitte nach der schleife auch ein test syso zb. "ende der schleife" rein, damit wir das ausschließen können


while(in.readBoolean()){
if(j < 200000){
System.out.println(in.read(buffer[j]));
}else{
in.read(tempBuffer);
//hier ein syso
}

j++;
}
// hier auch ein syso
 
Zuletzt bearbeitet:
Habe die sysos eingefügt und folgendes kommt rauß:

95.88.164.168 (ip)
1024 (empfangene bytes)
399 (empfangene bytes)
ende der schleife

Ich bin total am verzweifeln, ein Versuch bleibt mir noch bei einem völlig anderen PC das gleiche zu testen um auszuschließen, dass es an meinem Router liegt.

*Edit*

Ganz vergessen, das syso im else Teil wurde gar nicht aufgerufen. Die Socket Verbindung wird durch etwas externes unterbrochen. Deswegen kommt es zum Socket write Problem.
 
gut... da haben wir das problem doch: er ließt nur 2x was entweder bedeutet das file ist nur so groß(glaub ich jetzt mal nicht weils vorhin schon mehr war) oder vom server wird irgend etwas falsch gesendet / der client interpretiert was falsch an deinen steuer booleans. das problem ist nämlich: der client ließt das boolean, fängt an die daten zu lesen bis 1024, ließt wieder ein boolean und will wieder daten lesen. von den 2. daten sind aber noch nicht alle 1024 da, deswegen wird der buffer nicht voll und er versucht wieder ein boolean zu lesen. dieses boolean ist aber dann kein boolean sondern noch daten = exception und abbruch

dh du musst beim lesen prüfen wieviel schon in den buffer gelesen wurde, wenn noch keine 1024 gelesen wurden musst du solange lesen bis 1024 gelesen wurden und dann erst das nächste boolean lesen und dann wieder daten nach dem gerade beschriebenen schema

edit: bessere idee:
in der leseschleife machst du folgendes:


edit2: java tags hinzugefügt
Java:
while(in.readBoolean()){

while(in.available() < 1024) {
Thread.sleep(10);
}

if(j < 200000){
System.out.println(in.read(buffer[j]));
}else{
in.read(tempBuffer);
//hier ein syso
}

j++;
}
 
Zuletzt bearbeitet:
die exception kam auf dem server übrigens daher:

der client hört auf zu lesen und der server versucht zu schicken. auf dem client ist der netzwerkbuffer voll weil keine daten mehr geholt werden / bzw irgentwann du den stream schließt. der server will aber weiter schicken und kriegt per tcp keine informationen mehr wieviel noch möglich ist (siehe tcp:flowcontrol) damit er nicht überläuft, irgendwann kommts dann zum timeout was soviel wie connection reset by peer ist
 
Hey,
sehr gute Idee, habs gleich mal umgesetzt. Ich hatte mir schon gedacht, dass er mit boolean und bytes Daten durcheinander wirft.

Jetzt sieht die Ausgabe so aus:

1024
1024
1024
1024
1024

Und dann blockiert er dauerhaft, mit Ausgabe zeigt er mir an, dass er nur noch wartet.
Wenn ich mir in.available() ausgeben lasse zeigt er dauerhaft nur 471 an.
 
das liegt jetzt daran, dass deine datei warscheinlich zu ende ist

edit: ups lösungsansatz vergessen
wenn de in die [EDIT] schleife [/EDIT] kommst speicherste am besten immer in nen tmp buffer und hängts an den an bis du 1024 bytes hast UND prüfst auch bei jedem schleifendurchlauf ob am ende ein boolean ist, wenn ja musste die schleife abbrechen und den letzten buffer schreiben

edit:
deswegen habe ich ein datenprotokoll für meine netzwerkanwendungen in dieser form:
[int][bytes]
das int steht für die anzahl an bytes die dannach kommen, macht das leben viel leichter
 
Zuletzt bearbeitet:
Hm das wäre extrem seltsam, die Datei ist noch viel größer. Deswegen läd er über localhost auch schon sehr lange und sendet/empfängt eindeutig viel mehr.

Gibt es noch einen Grund warum er nicht mehr frei macht?

*Edit*

Vielen dank übrigens für deine Hilfe 😉 :applaus:
Wie setzt man das um, dass er das in nen tempBuffer schreibt, könnte ich hier while(in.available() < 1024) das Ganze so umbauen, dass er wenn weniger Bytes reinkommen diese zusammengehängt werden?
Bin mir nicht sicher ob ich das richtig verstanden habe.
 
Zuletzt bearbeitet:
1. lass dir aufm server auch mal ausgeben wie oft er versucht so einen 1024 byte datensatz zu schicken
2. vergleich die anzahl der datensätze mit dem client
3. mal gucken...
edit0:
4. poste nochmal die verändert version der client read schleife
edit1:
5. hast du icq, skype, msn, xfire, steam, irgendwas in der art? über das forum ist das nervig bei sowas intensivem
 
Zuletzt bearbeitet:
Java:
while(in.readBoolean()){
				while(in.available() < 1024){
					Thread.sleep(10);
				}
				
				if(j < 200000){
					System.out.println(in.read(buffer[j]));
				}else{
					in.read(tempBuffer);
				}
				
				j++;
			}
			System.out.println("while end");
			in.close();
			s.close();

Wie finde ich heraus wie oft der Server versucht einen 1024 Datensatz zu senden. Die Länge des buffer arrays ist ja immer 1024.

*Edit*

Skype, TeamSpeak, Steam habe ich, am liebsten Steam Steam Community :: ID :: Mr Toast
 

Zurück
Oben