Invalid Stream Header - Socket Transfer in Java - java

I have another problem.
This is a part of my client:
Socket socket = new Socket("127.0.0.1", 3000);
OutputStream out = socket.getOutputStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutput oo = null;
try {
oo = new ObjectOutputStream(bos);
oo.writeObject(mp3dataStrings);
byte[] serializedMP3 = bos.toByteArray();
out.write(serializedMP3);
out.flush();
} finally {
oo.close();
bos.close();
}
this is a part of my server:
ServerSocket clientConnect = new ServerSocket(port);
System.out.println("SimpleServer running on port" + port);
Socket clientSock = clientConnect.accept();
InputStream is = clientSock.getInputStream();
byte[] buffer = new byte[1024];
for (int i = 0; i < buffer.length; i++) {
int b = is.read();
buffer[i] = (byte) b;
if (b == -1 | b == 0) break;
}
ObjectInputStream stream = new ObjectInputStream(new ByteArrayInputStream(buffer));
String[][] songs = (String[][]) stream.readObject();
stream.close();
When I send my object (a String[][]) I get the exception invalid stream header: ACED0000.
I can't find what this means and what I have to do.
greets
Alex

You have made it far more complicated than you need to.
Socket socket = new Socket("127.0.0.1", 3000);
try {
ObjectOutputStream oo = new ObjectOutputStream(socket.getOutputStream());
oo.writeObject(mp3dataStrings);
oo.close();
} finally {
socket.close();
}
and
ServerSocket clientConnect = new ServerSocket(port);
System.out.println("SimpleServer running on port" + port);
Socket clientSock = clientConnect.accept();
try {
ObjectInputStream stream = new ObjectInputStream(clientSock.getInputStream());
String[][] songs = (String[][]) stream.readObject();
} finally {
clientSock.close();
}

I agree with Peter Lawrey's answer, however the problem in your original code stems from the exit condition in the byte buffer population code
byte[] buffer = new byte[1024];
for (int i = 0; i < buffer.length; i++) {
int b = is.read();
// THIS ARE PROBLEM LINES
buffer[i] = (byte) b;
if (b == -1 | b == 0) break;
}
ObjectInputStream stream =
new ObjectInputStream(new ByteArrayInputStream(buffer));
You should only exit this loop when you've detected End-Of-Stream condition. In other words you should never consider b==0, as it is a valid part of the ObjectInputStream.
Second, you should not assign the byte to the buffer before checking for break condition.
Third, if you initialize ByteArrayInputStream, you should pass only the number of bytes that contain input, not the whole buffer itself.
Corrected block should be like this:
// How do you know if 1024 is enough to get all data?
// For the sake of this example, assume it's enough
byte[] buffer = new byte[1024];
int count = 0;
for (; count < buffer.length; count++) {
int b = is.read();
if ( b == -1 )
{
// exit only on End-Of-Stream, and do not record
// this result into the buffer
break;
}
buffer[count] = (byte) b;
}
ObjectInputStream stream =
new ObjectInputStream(
// Note, that we are now passing the number of 'active' bytes in the buffer
new ByteArrayInputStream(buffer, 0, count)
);

Related

Voip UDP adding a sequence number (preparing for packetloss)

Note: I'm currently learning UDP and how effective a VoIP system would be in comparison with a TCP system, I've already done TCP so please no one comment TCP is better etc..
So I'm trying to add a sequence number to the packets so I can order them on the server end and prepare for any lost packets, by repeating the previous for example
Problem: I read a stackoverflow that said using DataOutputStreams is a good way to go about this, so I implemented it. however when using the code dos.writeInt(sequenceNumber++); I get a horrible repetitive crackle. I was thinking maybe the problem is the amount of bytes that im sending.
Thank you in advance, any pointers will be great
boolean running = true;
try {
AudioRecorder recorder = new AudioRecorder();
int sequenceNumber = 0;
while (running) {
byte[] tempBuffer = recorder.getBlock();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(baos);
dos.write(tempBuffer);
dos.writeInt(sequenceNumber++);
dos.flush();
DatagramPacket sendPacket = new DatagramPacket(baos.toByteArray(), baos.size(), clientIP, PORT);
sending_socket.send(sendPacket);
}
recorder.close();
} catch (Exception e) {
System.out.println("Error" + e);
Server end:
byte[] buffer = new byte[512];
byte[] temp = new byte[512];
try {
// CODE TO RECEIVE THE AUDIO
AudioPlayer player = new AudioPlayer();
int expectedValue = 0;
while (running) {
//Vector used to store audio blocks (32ms/512bytes each)
Vector<byte[]> voiceVector = new Vector<>();
// creates a new udp packet to receive the audio
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
receiving_socket.receive(packet);
// creates a byte array from the data
byte[] udpPacketBytes = packet.getData();
ByteArrayInputStream baos = new ByteArrayInputStream(udpPacketBytes);
DataInputStream dos = new DataInputStream(baos);
int receivedValue = dos.readInt();
if (receivedValue == expectedValue) {
byte[] filteredByteArray = Arrays.copyOfRange(udpPacketBytes, 4, udpPacketBytes.length - 4);
voiceVector.add(filteredByteArray);
Iterator<byte[]> voiceItr = voiceVector.iterator();
while (voiceItr.hasNext()) {
player.playBlock(voiceItr.next());
}
} else {
// play the previous again
byte[] filteredByteArray = Arrays.copyOfRange(temp, 4, temp.length - 4);
voiceVector.add(filteredByteArray);
Iterator<byte[]> voiceItr = voiceVector.iterator();
while (voiceItr.hasNext()) {
player.playBlock(voiceItr.next());
}
// play the current one
byte[] fba = Arrays.copyOfRange(udpPacketBytes, 4, udpPacketBytes.length - 4);
voiceVector.add(fba);
Iterator<byte[]> vItr = voiceVector.iterator();
while (vItr.hasNext()) {
player.playBlock(vItr.next());
}
}
System.out.println(receivedValue + " " + expectedValue);
expectedValue = receivedValue + 1;
temp = packet.getData();
}
} catch (Exception e) {
System.out.println("yo");
}
//Close the socket
receiving_socket.close();
You are writing the sequence number but you are not reading or removing it so your sequence number ends up in the audio.
I suggest you read the same format you write.

Issues sending jpg-image over java socket using datainput/-outputstream

I wish to send a JPG-image from a client to a server over a TCP socket connection. I convert the file to a byte array in the client then send it to the server after having sent the array length. The server reads the data one byte at a time from the socketinputstream to a new bytearray which is then written to a jpg-file. The data however is corrupted and this image cannot be viewed. Below is core java code for client and server.
Client:
Socket s = new Socket("localhost", 666);
DataOutputStream dos = new DataOutputStream(s.getOutputStream());
String imgPath = "C:/Users/huehuehue/Documents/Uni/D0036D/prick1.JPG";
File file = new File(imgPath);
byte[] b = new byte[(int) file.length()];
FileInputStream fis = new FileInputStream(file);
fis.read(b);
fis.close();
dos.writeInt((int) file.length());
dos.flush();
dos.write(b, 0, b.length);
dos.flush();
Server:
ServerSocket serverSocket = new ServerSocket(666);
Socket connect = serverSocket.accept();
DataInputStream dis = new DataInputStream(connect.getInputStream());
File file = new File("C:/Users/huehuehue/Documents/Uni/D0036D/PLAYERprick.JPG");
FileOutputStream fos = new FileOutputStream(file);
int arrlen = dis.readInt();
byte[] b = new byte[arrlen];
int i = 0;
for(i = 0; i < arrlen; i++) {
b[i] = dis.readByte();
i++;
}
fos.write(b, 0 , b.length);
I can't see why this wouldn't work and any help or suggestions is greatly appreciated.
int arrlen = dis.readInt();
byte[] b = new byte[arrlen];
int i = 0;
for(i = 0; i < arrlen; i++) {
b[i] = dis.readByte();
i++;
}
You're incrementing i twice so you're ignoring half the input, and writing what you don't ignore into the wrong slots. Fortunately there is an easier way, which is also much more efficient:
int arrlen = dis.readInt();
byte[] b = new byte[arrlen];
dis.readFully(b);
NB fis.read(b); isn't valid. You can't assume it fills the buffer. You should use DataInputStream.readFully() here too.
You need to match both ends of the socket and your client doesn't fill your byte[] fully; instead your client could send each byte as it reads it. And, since Java provides BufferedInputStream you don't have to manually use and tweak a byte[] buffer directly. Instead you could do something like,
Socket s = new Socket("localhost", 666);
String imgPath = "C:/Users/huehuehue/Documents/Uni/D0036D/prick1.JPG";
File file = new File(imgPath);
try (InputStream is = new BufferedInputStream(new FileInputStream(file));
DataOutputStream dos = new DataOutputStream(s.getOutputStream());) {
dos.writeLong(file.length()); // <-- remember to read a long on server.
int val;
while ((val = is.read()) != -1) {
dos.write(val);
}
dos.flush();
}
Also, your server could use the similar BufferedOutputStream to get the benefit of a buffer like
ServerSocket serverSocket = new ServerSocket(666);
File file = new File("C:/Users/huehuehue/Documents/Uni/D0036D/PLAYERprick.JPG");
try (Socket s = serverSocket.accept();
DataInputStream dis = new DataInputStream(
s.getInputStream());
OutputStream fos = new BufferedOutputStream(
new FileOutputStream(file));) {
long arrlen = dis.readLong();
for (long i = 0; i < arrlen; i++) {
fos.write(dis.read());
}
fos.flush();
}
without having to manually manage it. Notice the above use BufferedInputStream and BufferedOutputStream to manage the buffering as an optimization. You could remove them and read and write directly from the File streams.

Socket closed issues

I have a server and client connection using sockets to transfer files, but if I want to be able to send strings to the server from the client upon user JButton actions, it throws socket closed errors (Because I used dos.close() in the Sender() constructor). The problem is, if I don't use dos.close(), the client program won't run/init the UI frame. What am I doing wrong? I need to be able to send files when the program first runs then send data later.
Sender:
public Sender(Socket socket) {
List<File> files = new ArrayList<File>();
files.add(new File(Directory.getDataPath("default.docx")));
files.add(new File(Directory.getDataPath("database.db")));
try {
BufferedOutputStream bos = new BufferedOutputStream(socket.getOutputStream());
DataOutputStream dos = new DataOutputStream(bos);
dos.writeInt(files.size());
for (File file : files) {
dos.writeLong(file.length());
dos.writeUTF(file.getName());
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
int theByte = 0;
while ((theByte = bis.read()) != -1) {
bos.write(theByte);
}
bis.close();
}
dos.close(); // If this is disabled, the program won't work.
} catch (Exception e) {
e.printStackTrace();
}
}
Downloader:
public static byte[] document;
public Downloader(Socket socket) {
try {
BufferedInputStream bis = new BufferedInputStream(socket.getInputStream());
DataInputStream dis = new DataInputStream(bis);
int filesCount = dis.readInt();
for (int i = 0; i < filesCount; i++) {
long size = dis.readLong();
String fileName = dis.readUTF();
if (fileName.equals("database.db")) {
List<String> data = new ArrayList<String>();
BufferedReader reader = new BufferedReader(new InputStreamReader(bis));
String line;
while ((line = reader.readLine()) != null) {
if (line.trim().length() > 0) {
data.add(line);
}
}
reader.close();
parse(data);
} else if (fileName.equals("default.docx")) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
for (int x = 0; x < size; x++) {
bos.write(bis.read());
}
bos.close();
document = bos.toByteArray();
}
}
//dis.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Your first receive loop in the client terminates at EOS, which only happens when you close the socket in the sender, which you don't want to do. You're sending the length ahead of the file in each case so the receiving code should look like this in both cases:
long total = 0;
while ((total < size && (count = in.read(buffer, 0, size-total > buffer.length ? buffer.length : (int)(size-total))) > 0)
{
total += count;
out.write(buffer, 0, count);
}
out.close();
That loop reads exactly size bytes from the socket input stream and writes it to the OutputStream out, whatever out happens to be: in the first case, a FileOutputStream, in the second, a ByteArrayOutputStream.

Transfer Java Object through Sockets, Byte[]

Would you take a look over this?:
This is my client:
try {
Socket socket = new Socket("127.0.0.1", 3000);
OutputStream out = socket.getOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(mp3data);
oos.close();
byte[] bytes = baos.toByteArray();
out.write(bytes);
}
catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This is my server:
int port = 3000;
try {
ServerSocket clientConnect = new ServerSocket(port);
System.out.println("SimpleServer running on port" + port);
Socket clientSock = clientConnect.accept();
InputStream is = clientSock.getInputStream();
byte[] buffer = new byte[1024];
int read = is.read(buffer);
ObjectInputStream ois = new ObjectInputStream(is);
MP3[] songs = (MP3[])ois.readObject();
clientSock.close();
// HTML erzeugen
Website site = new Website("index2.html",songs);
} catch (Exception e) {
System.out.println (e);
}
It ain't work. I don't get any exceptions but the Website-Constructor isn't called.
You assume that the whole byte array is read in just one call to read(), and has a length of exactly 1024 bytes. That's not the case (unless you're extremely lucky). Moreover, your ObjectInputStream is wrapping the InputStream from which you have already read the bytes (or some of the bytes) constituting the message. And also, the bytes written by the sender are not flushed.
Don't ignore the result of the call to is.read(): It tells you how many bytes have actually been read. And until it's not -1, you should continue to read, in a loop.
Read the Java tutorial on byte streams.
That said, you're making things difficult. Why don't you write the object directly to the socket output stream, and read the object directly from the socket input stream at the other side?
int port = 3000;
try {
ServerSocket clientConnect = new ServerSocket(port);
System.out.println("SimpleServer running on port" + port);
Socket clientSock = clientConnect.accept();
InputStream is = clientSock.getInputStream();
byte[] buffer = new byte[1024];
for (int i = 0; i < buffer.length; i++) {
int b = is.read();
if (b ==-1) break;
buffer[i] = (byte) b;
}
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(buffer));
MP3[] songs = (MP3[])ois.readObject();;
ois.close();
clientSock.close();

Java Socket synchronization behavior

I tried to solve the problem in many ways but without success and I have also looked for information in this forum but with same results, so here we go.
I am actually doing a server daemon that accepts client requests and then it (the server) transfers all the files contained in a specific folder. I'm going to post the code of the sendFileData (on the server) and the receiveFileData (on the client).
The server uses:
public static void sendFileData(File file, Socket socket) throws FileNotFoundException, IOException, SocketException {
byte[] auxiliar = new byte[8192];
byte[] mybytearray = new byte[(int) file.length()];
int longitud = mybytearray.length;
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
bis.read(mybytearray, 0, longitud);
DataOutputStream os = new DataOutputStream(socket.getOutputStream());
int paquetes = longitud / 8187;
int resto = longitud % 8187;
int i = 0;
while(i<paquetes){//The length goes on the first 4 bytes and the 5th tells if there are more packets to send (8192 bytes or less).
byte[] bytes = ByteBuffer.allocate(4).putInt(8187).array();
auxiliar[0] = bytes[0];
auxiliar[1] = bytes[1];
auxiliar[2] = bytes[2];
auxiliar[3] = bytes[3];
auxiliar[4] = 1;
for(int j = 5; j < 8192; j++){
auxiliar[j] = mybytearray[i*8187+(j-5)];
}
os.write(auxiliar, 0, 8192);
i+=1;
}
if(resto > 0){
byte[] bytes = ByteBuffer.allocate(4).putInt(resto).array();
auxiliar[0] = bytes[0];
auxiliar[1] = bytes[1];
auxiliar[2] = bytes[2];
auxiliar[3] = bytes[3];
auxiliar[4] = 0;
for(int j = 5; j < resto+5; j++){
auxiliar[j] = mybytearray[i*8187+(j-5)];
}
os.write(auxiliar, 0, resto+5);
}
os.flush();
}
And in the client side:
public static void receiveFileData(String nombreFichero, Socket s) throws IOException{
File monitored = new File(nombreFichero);
if(monitored.exists() == false){
monitored.createNewFile();
}
byte[] mybytearray;
DataInputStream is = new DataInputStream(s.getInputStream());
FileOutputStream fos = new FileOutputStream(monitored);
BufferedOutputStream bos = new BufferedOutputStream(fos);
int bytesRead = 0;
int hasNext = 1;
do {
bytesRead = is.readInt();//Leo longitud
try {
Thread.sleep(1);// HERE!!!!
} catch (InterruptedException e) {
}
// System.out.println("Bytes read "+bytesRead );
if(bytesRead <= 8187 && bytesRead > 0){
// System.out.println("Bytes leídos "+bytesRead );
hasNext = is.readByte();//Leo si hay más datos por enviar
mybytearray = new byte[bytesRead];
is.read(mybytearray);
if(monitored.exists()){
synchronized(monitored){
bos.write(mybytearray, 0, mybytearray.length);
}
}
mybytearray = null;
}else{
System.out.println("Fuera de rango "+bytesRead);
}
}while(hasNext == 1);
bos.close();
mybytearray = null;
System.out.println("Fichero recibido: "+monitored.getAbsolutePath());
}
In the receiveFileData code, if I do not put a Thread.sleep(1) or a System.out.println() or whatever who takes time to execute, I am not receiving the data in the correct way on the client, because readInt() returns a very high number randomly negative or positive (which implies Heap out of memory and other exceptions).
Sure it's something about synchronization but I think the transfering schema between the two methods is correct (maybe the client is too slow and server too fast).
What is happening?? Because I do not want to put a Thread.sleep, this is not good programming here I think.
Thank you so much!
is.read(bytes) is not guaranteed to fill the supplied byte array. You need to check its return value to see how many bytes were read or (better) use readFully().
The sleep() probably just allows time for all bytes to have been returned from the socket.

Categories