Bild empfangen über Socket

  • Antworten:70
Gelöschter Account
  • Forum-Beiträge: 2.492

24.02.2014, 17:24:18 via Website

Hallo,
ich habe eine Socket Verbindung zwischen Client und Server und Textnachrichten zu versenden klappt. Das Empfangen habe ich so gelöst:
1BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
2String st = null;
3st = input.readLine();
4mClientMsg = st;
5myUpdateHandler.sendMessage(m);

Doch jetzt will ich ein Bild empfangen. Und zwar bekomme ich ein Byte[] und verarbeite das. Aber leider wird dann auf dem Bildschirm nichts angezeigt und es kommt auch kein Fehler:

1InputStream stream = s.getInputStream();
2final byte[] bytes = readFully(stream);
3Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
4ImageView view = new ImageView(MyServer.this);
5view.setImageBitmap(bmp);
6lChat.addView(view);
7
8public static byte[] readFully(InputStream input) throws IOException
9 {
10 byte[] buffer = new byte[8192];
11 int bytesRead;
12 ByteArrayOutputStream output = new ByteArrayOutputStream();
13 while ((bytesRead = input.read(buffer)) != -1)
14 {
15 output.write(buffer, 0, bytesRead);
16 }
17 return output.toByteArray();
18 }

Weiß jemand was ich ändern muss?

Gruß
Lars

— geändert am 24.02.2014, 17:24:58

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

24.02.2014, 17:26:18 via Website

Wie sind die Bytes des Bildes denn kodiert?
Wie verschickst du das Bild vom Server?

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

24.02.2014, 17:27:30 via Website

Das ist die Methode zum Versenden des Bildes:
1ByteArrayOutputStream stream = new ByteArrayOutputStream();
2 bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
3 byte[] byteArray = stream.toByteArray();
4 OutputStream os;
5 try {
6 os = MyServer.socket.getOutputStream();
7 os.write(byteArray,0,byteArray.length);
8 os.flush();
9 } catch (IOException e) {
10 // TODO Auto-generated catch block
11 e.printStackTrace();
12 }

— geändert am 24.02.2014, 17:27:50

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

24.02.2014, 17:34:32 via Website

Wenn du beim sendenden ByteArrayOutputStream benutzt solltest du beim lesen dem ByteArrayInputStream nehmen

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

24.02.2014, 18:00:17 via Website

Also dann:
ByteArrayInputStream stream = (ByteArrayInputStream) s.getInputStream();
und dann so wie zuvor oder wie meinst du das?

Antworten
impjor
  • Forum-Beiträge: 1.793

24.02.2014, 18:06:00 via Website

Warum so kompliziert?

Gib dem Bitmap einfach deinen OutputStream:

1bmp.compress(Bitmap.CompressFormat.PNG, 100, MyServer.socket.getOutputStream());

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

24.02.2014, 18:10:13 via Website

Ist das jetzt für das Senden oder für das Empfangen?

Ich dachte OutputStream ist so grob gesagt immer senden und InputStream ist empfangen.

Antworten
impjor
  • Forum-Beiträge: 1.793

24.02.2014, 18:15:18 via Website

Ja, ist fürs versenden gedacht.

Du kannst ja mal prüfen ob die compress(...)-Methode true zurückliefert... Sonst kann das Bitmap über BitmapFactory.decode(...) nicht gelesen werden.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

24.02.2014, 21:40:11 via Website

Ich verstehe jetzt nicht was du meinst.
Das Bild müsste doch eigentlich als Byte[] schon übergekommen sein und muss jetzt nur noch wieder zu einem Bild gemacht werden oder?

Edit: wenn ich das compress in ne if Abfrage stecke sagt er mir das true zurückkommt also heißt das das das Bild richtig komprimiert werden kann also liegt der Fehler beim Empfänger oder?

— geändert am 24.02.2014, 21:43:45

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

24.02.2014, 21:51:03 via App

Genau, du musst beim Empfänger die Bytes wieder dekomprimieren und in ein Bmp laden

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

24.02.2014, 21:58:49 via Website

Okay und genau da weiß ich nicht weiter, weil kein Bild angezeigt wird

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

24.02.2014, 23:34:16 via App

Dann musst du die einzelnen Bytes vergleichen, ob sie auch alle richtig empfangen werden. Sonst musst du nen anderen inputstream etc. nehmen

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 16:45:27 via Website

Hab versucht die Bytes zu loggen aber wird nichts in der Logcat angezeigt

Hab jetzt so gesendet:
[code]
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byte[] byteArray = stream.toByteArray();
OutputStream os;
try {
os = MyClient.socket.getOutputStream();
os.write(byteArray,0,byteArray.length);
for(int i = 0; i < byteArray.length; i++){
Log.d("i", ""+byteArray[i]);
}
os.flush();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
[/code]

Und so versucht zu empfangen:
1if (s == null){
2 s = ss.accept();
3 }
4 BufferedReader input = new BufferedReader(new InputStreamReader(s.getInputStream()));
5
6 InputStream stream = s.getInputStream();
7 final byte[] bytes = readFully(stream);
8 Bitmap bmp = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
9 ImageView view = new ImageView(MyServer.this);
10 view.setImageBitmap(bmp);
11 lChat.addView(view);
12
13 String st = null;
14 st = input.readLine();
15 mClientMsg = st;//mybytearray2.toString()
16 myUpdateHandler.sendMessage(m);
17 } catch (IOException e) {
18 // TODO Auto-generated catch block
19 e.printStackTrace();
20 }

Aber es tut sich immer noch nichts.
Habt ihr eine Idee was ich ändern muss?

— geändert am 25.02.2014, 16:46:25

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

25.02.2014, 16:47:53 via Website

Nimm den Debugger mit einem Brakepoint und schau dir einfach den Inhalt deines ByteArrays an. #
Dafür musst du nix in LogCat schreiben lassen

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
impjor
  • Forum-Beiträge: 1.793

25.02.2014, 16:49:18 via Website

Wenn nichts im LogCat steht könnte es sein, dass gar keine Daten im byte[] sind. Da würde ich mal mit dem Debuger nachsehen...

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 17:01:31 via Website

Hab jetzt erstmal den Sender mit dem Debugger gestartet aber der zeigt gar keine Variablen in der Variables View an.

Antworten
impjor
  • Forum-Beiträge: 1.793

25.02.2014, 17:04:10 via Website

Lars F.
der zeigt gar keine Variablen in der Variables View an.
Bitte, wie?

Einfach Breakpoint setzten, nachdem das byte[] gefüllt wurde, und dann dieses sich ansehen...

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 17:20:01 via Website

Ja hat jetzt funktioniert also da scheint was drin zu sein.
Jetzt versuch ich es beim Empfänger, aber da kommt der gar nicht bis zu dem Breakpoint (ich habe den hinter das byte[] gesetzt)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 17:27:37 via Website

Bis zu dem s = ss.accept()
und dann zeigt er keine Variablen mehr an und ich kann auch nicht mehr auf "Weiter" drücken.
Fehler gibt es keine.

Antworten
impjor
  • Forum-Beiträge: 1.793

25.02.2014, 17:29:28 via Website

Dann wartet Android ewig auf eine Verbindung. Ist dein Android-Gerät der Server? Gab hier letztens auch einen Thread dazu...
Stelle sicher, dass der Server erreicht werden kann und du die richtig ip-Adresse nutzt.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 17:53:16 via Website

Ja mein Smartphone ist der Server.
Also es besteht eine Verbindung aber nur beim ersten Mal, dann muss ich wieder alles deinstallieren und neu draufziehen damit es wieder klappt.

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

25.02.2014, 17:56:00 via Website

Aber du hast gesagt, dass Textnachrichten Funktionieren oder?
Es liegt nur an dem Encodieren und interpretieren der Bytes am Empfänger.
Das mit dem deininstallieren musst du wahrscheinlich machen, da deine Connection nicht geschlossen wird?
Sonst müsstest du die immer neu aufbauen können und nicht einfach Apps neu installieren.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 17:59:03 via Website

Ja also wenn das mit der Verbindung klappt und ich das empfangen von dem Bild auskommentiert hab klappt das.
Ich benutze ss und s.close also ServerSocket und Socket. Reicht das nicht zum schließen?

Edit: Wenn ich das decodieren von dem Bild auskokmmentiert habe aber trotzdem eins sende, empfange ich viele komische Zeichen (bzw manchmal nur: ?PNG) also kommt da anscheinend wohl etwas an.

— geändert am 25.02.2014, 18:05:08

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 18:59:12 via Website

Habe den InputStream mal zu einem BufferedInputStream gemacht und hab jetzt noch bisschen gedebuggt und da ist mir aufgefallen:
Der BufferedInputStream wird aufgebaut aber dann in der nächsten Zeile, wenn der stream in das byte[] soll passiert dann nichts mehr also liegt da wahrscheinlich der Fehler.

Antworten
impjor
  • Forum-Beiträge: 1.793

25.02.2014, 20:42:43 via App

Also teste mal folgendes:
1. Wird die Methode readFully() aufgerufen?
2. Was gibt sie zurück?
3. Gibt sie überhaupt etwas zurück?

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 20:55:29 via Website

Okay
1) Ja wird aufgerufen
2) Kann ich nicht sagen weil er bis zu dem Breakpoint bei dem return nicht kommt.
In dem OutputStream output ist aber was drin und im buffer anscheinend auch (also da sind mehrere positive und negative Zahlen drin das ist doch richtig oder?)

Es kommt ganz sicher was an, weil wenn ich auf Senden drücke ändern sich beim debuggen immer die Werte von dem buffer und output

— geändert am 25.02.2014, 21:13:24

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

25.02.2014, 21:56:35 via Website

Sehr geil! Er sendet es :)
Ich musste noch ein new Runnable dann einfügen um das Bild darzustellen und dann hat es geklappt.
Vielen Dank :)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

26.02.2014, 16:43:01 via Website

Das Problem ist jetzt nur das er dann keine Texte mehr empfängt.
Kann man irgendwie abfragen ob es jetzt ein Bild oder ein Text wird?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

26.02.2014, 16:53:46 via Website

Dann musst du dein eigenes Protokoll kodieren, somit hast du am Anfang ca.5-10 Bytes in denen du kodierst, was es ist, ggf. noch zeit und Namen oder so.
Dieses musst du dann an beiden Seiten lesen und schreiben können, sodass man immer vorher weisstob es text oder Bild sind.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
impjor
  • Forum-Beiträge: 1.793

26.02.2014, 16:54:02 via App

Sende doch ein byte, wenn Text kommt und ein anderes, wenn du ein Bild sendest. Am besten dazu noch die Anzahl an Bytes senden, die zum Bild/Text gehören.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

26.02.2014, 17:05:24 via Website

Aber die Abfrage was für Bytes das sind kann ich ja erst machen wenn ich die schon empfangen hab und ich glaub dann ist es schon zu spät.
Oder muss ich den Text dann auch in Bytes übertragen?

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

26.02.2014, 17:10:49 via Website

Warum zu spät?
Wenn du es empfangen hast, schaust du was in den ersten Bytes drin steht.
Wenn es die Kombination für text ist, dann lässt du den Input stream oä. vom text duchlaufen und sonst den vom bild

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
impjor
  • Forum-Beiträge: 1.793

26.02.2014, 17:12:56 via App

Alles wird in bytes übertragen.
Zuerst sendest du ein byte, das dir sagt, ob Text oder Bild kommt. Dann die Anzahl an bytes. Genau diese Anzahl an Bytes ließt du dann ein (wie bei deinem Bild, nur nicht bis zum Ende, sondern eben die Anzahl). Der Text kann dann über new String(byte-Array) erstellt werden.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

26.02.2014, 21:54:08 via Website

Den Text sende ich über den PrintWriter deswegen komme ich da gar nicht an ein byte[] dran.
Edit: ich versuche jetzt string.getBytes() um die Bytes des Textes zu bekommen und versende die dann über den PrintWriter geht das so?

— geändert am 26.02.2014, 21:58:34

Antworten
impjor
  • Forum-Beiträge: 1.793

26.02.2014, 22:02:14 via App

Du hast doch einen OutputStream vom Socket. Dann kannst du einfach OutputStream#write() benutzen und musst keinen PrintWriter o.ä. bemühen.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.02.2014, 14:37:13 via Website

Super das klappt jetzt alles auch so weit.
Nur kann ich jetzt nur eine Sache senden und dann ist vorbei. Wahrscheinlich weil ich ja den OutputStream close. Kann man den irgendwie wieder "öffnen".

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.02.2014, 14:40:01 via Website

Da stehts drinnen:
http://developer.android.com/reference/java/io/OutputStream.html

(Tipp: Nein, du musst die App neustarten oder die OuputStram variable mit einem neuen überschreiben.)

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

28.02.2014, 14:43:16 via Website

Kann ich anstatt close nicht flush nehmen?
Edit: Ne anscheinend nicht ;)

— geändert am 28.02.2014, 14:47:56

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

28.02.2014, 14:46:16 via Website

Was meinst du mit statt Close?
Wenn der OutStream closed ist, dann machst du einfach einen neuen auf und überschreibst die Variable des alten.
Was ist daran das Problem?

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
impjor
  • Forum-Beiträge: 1.793

28.02.2014, 14:48:02 via App

Du kannst einfach flush() anstelle von close() benutzen.
Sende einfach bevor du das Bild versendest die Anzahl an Bytes, aus denen das Bild besteht und ließ nur diese Anzahl ein.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

02.03.2014, 11:31:27 via Website

Das unterscheiden ob es ein Bild oder Text ist geht jetzt.
Aber mit flush anstatt close geht es leider gar nicht. Also dann kommt nichts über, und überschreiben hab ich so versucht:
1BufferedOutputStream os;
2 os = null;
3 os = new BufferedOutputStream(socket.getOutputStream());
4 os.write(datas);
5 os.close();

da kam dann aber auch nichts über.

Also ohne flush und überschreiben sieht mein senden des Textes so aus:
[code]
try {
String str = et.getText().toString();
byte[] datas = new byte[str.getBytes().length+2];
datas[0] = 99;
datas[1] = 123;
byte[] text = str.getBytes();
for(int i = 2; i < datas.length; i++){
datas[i] = text[i-2];
}
BufferedOutputStream os;//Hier hätte ich fürs überschreiben os = null gesetzt
os = new BufferedOutputStream(socket.getOutputStream());
os.write(datas);
os.close();//Hier hätte ich einfach anstatt close flush verwendet
[/code]


Und mein empfangen so:
[code]
BufferedInputStream stream;
try {
if (s == null){
s = ss.accept();
}
stream = new BufferedInputStream(s.getInputStream());

final byte[] bytes = readFully(stream);
if(bytes.length > 0){
if(bytes[0] == 99 && bytes[1] == 123){
String st = null;
byte[] text = new byte[bytes.length-2];
for(int i = 0; i < bytes.length-2; i++){
text[i] = bytes[i+2];
}
st = new String(text);
mClientMsg = st;
myUpdateHandler.sendMessage(m);
}


public byte[] readFully(InputStream input) throws IOException
{
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
while ((bytesRead = input.read(buffer)) != -1)
{
output.write(buffer, 0, bytesRead);
}
output.flush();
return output.toByteArray();
}
[/code]

So kann ich nur einmal senden und dann nicht mehr. Möglicherweise hab ich das flush falsch gesetzt oder falsch überschrieben.

Edit: Warum wird das nicht als code angezeigt?

— geändert am 02.03.2014, 11:59:43

Antworten
impjor
  • Forum-Beiträge: 1.793

02.03.2014, 11:55:19 via Website

Ich kommentiere mal deinen Code:
[code]
try {
String str = et.getText().toString();
byte[] datas = new byte[str.getBytes().length+2];
datas[0] = 99; //Wofür steht die 99?
datas[1] = 123;//Wofür die 123?
byte[] text = str.getBytes();
for(int i = 2; i < datas.length; i++){
datas[i] = text[i-2];
}
BufferedOutputStream os;//Warum einen BufferedOutputStream? Benutze einfach socket.getOutputStream().write(datas);
os = new BufferedOutputStream(socket.getOutputStream());
//Du musst vorher noch die Länge der Bytes senden
os.write(datas);
os.close();//Hier dann flush verwenden
[/code]

[code]
BufferedInputStream stream;
try {
if (s == null){
s = ss.accept();
}
stream = new BufferedInputStream(s.getInputStream());

final byte[] bytes = readFully(stream);
[...]
}


public byte[] readFully(InputStream input) throws IOException
{
int count = [...]; //Hier nund die Anzahl der Bytes auslesen, die du gesendet hast
byte[] buffer = new byte[count];
for (int i = 0; i < count; i++) {
buffer[i] = (byte) input.read();
}
return buffer;
}
[/code]
LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

02.03.2014, 12:24:03 via Website

Ich hab gedacht die zwei Zahlen am Anfang mach ich um beim Empfänger unterscheiden zu können ob es ein Bild oder Text ist.

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

02.03.2014, 12:30:27 via Website

Na ja so ist das aber Sehr unschön.
Normalerweise macht man sich dann ein eigenes Protokoll und eine Klasse dafür. Dann hat man keine Probleme beim Schreiben und wieder lesen, da das ja deine Protokoll Klasse macht. Somit musst du dein Protokoll einmal Definieren und die nötigen Funktionen schreiben und du musst nicht immer die Bytes von Hand hinzufügen/lesen. Und woher sollen wir das wissen, dass deine Zahlen für die Unterscheidung sind, du hast ja keine Kommentare am Code..

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

02.03.2014, 12:36:00 via Website

Achso ich dachte ihr habt das so gemeint.
Aber mit dem flush funktioniert das so jetzt auch nicht. Bis zum flush funktioniert alles und dann gibt er mir den letzten Error (Exception e) aus.

Edit: Es liegt an dem:
socket.getOutputStream().write(datas);
als ich das durch den BufferedOutputStream wieder ersetzt habe hat es wieder funktioniert

— geändert am 02.03.2014, 12:39:13

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

02.03.2014, 12:39:35 via Website

Was ist denn der Error?
LogCat?
Wieso nur Exception e? Du kannst doch Spezifische exceptions festlegen.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
Gelöschter Account
  • Forum-Beiträge: 2.492

02.03.2014, 13:01:52 via Website

Es kommt ja kein Fehler er macht einfach nur nicht weiter und geht dann in den Exception e zweig.
Ja hab ich ja auch aber er nimmt trotzdem den.

Pascal P wie meintest du das denn mit dem überschreiben vielleicht klappt das ja.

— geändert am 02.03.2014, 13:04:03

Antworten
impjor
  • Forum-Beiträge: 1.793

02.03.2014, 13:06:58 via Website

Lars F.
Es kommt ja kein Fehler er macht einfach nur nicht weiter und geht dann in den Exception e zweig.
Also kommt doch ein Fehler. Den musst du schon nennen.

LG

Liebe Grüße impjor.

Für ein gutes Miteinander: Unsere Regeln
Apps für jeden Einsatzzweck
Stellt eure App vor!

Antworten