Transfer Java Object through Sockets, Byte[] - java

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();

Related

How to create an input stream whose source is the received packet (ByteArrayInputStream and DataInputStream)?

This is a portion of my code (Multicast subscriber to images)
public void subscribe() throws IOException {
byte[] b = new byte[100];
DatagramPacket datagram = new DatagramPacket(b, b.length, groupAddress, localPort);
MulticastSocket socket = new MulticastSocket(localPort);
socket.joinGroup(groupAddress);
socket.send(datagram);
while(true) {
socket.receive(datagram);
System.err.println("Received " + datagram.getLength() +
" bytes from " + datagram.getAddress());
datagram.setLength(b.length);
socket.leaveGroup(groupAddress);
socket.close();
}
Here is the task:
Create an input stream whose source is the received packet (e.g. ByteArrayInputStream and DataInputStream).
this is publisher:
private void castOneImage(DatagramSocket socket, String imageFn, SocketAddress groupSocketAddress) {
byte[] imageBytes = null;
try (InputStream in = getClass().getClassLoader().getResourceAsStream(imageFn);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream()) {
if (in == null) {
throw new FileNotFoundException("Cannot open image file " + imageFn);
}
int b;
while ((b = in.read()) != -1) {
byteOut.write(b);
}
imageBytes = byteOut.toByteArray();
byteOut.reset();
ByteBuffer byteBuffer = ByteBuffer.allocate(Integer.SIZE / 8);
byteBuffer.putInt(imageBytes.length);
byteOut.write(byteBuffer.array());
byteOut.write(imageBytes);
imageBytes = byteOut.toByteArray();
DatagramPacket packet = new DatagramPacket(imageBytes, imageBytes.length, groupSocketAddress);
socket.send(packet);
} catch (IOException e) {
// if there is an error for this image, we soldier on hoping other images may be good
LOGGER.warn("I/O error: " + e.getMessage(), e);
}
}
Use a ByteArrayInputStream:
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(datagram.getData(), datagram.getOffset(), datagram.getLength()));
And move the close() outside the loop. You don't have to leave the group explicitly if you're about to close the socket.
EDIT To reconstitute the image data:
int length = dis.readInt();
byte[] image = new byte[length];
dis.readFully(image);
But of course as datagrams know their own length, you didn't really need to send or receive the length word at all.

Socket closed exception when trying to transfer a file

I am trying to transfer a file from server to client using Java and TCP, however on the client-side I am getting a socket closed exception, whereas the server has no errors when attempting to transfer the file. I am confused about this error because I did not close the socket before trying to read from it. The server accepts the connection and sends the file, but the client gets that error. Any suggestion?
The error is:
java.net.SocketException: Socket closed
Server thread's run function:
public void run() {
System.out.println("Service thread running for client at " + socket.getInetAddress() + " on port " + socket.getPort());
try {
File file = new File("hank.txt");
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
OutputStream os = socket.getOutputStream();
byte[] contents;
long fileLength = file.length();
long current = 0;
long start = System.nanoTime();
while(current!=fileLength) {
int size = 1000;
if(fileLength - current >= size) {
current += size;
}
else {
size = (int)(fileLength - current);
current = fileLength;
}
contents = new byte[size];
bis.read(contents,0,size);
os.write(contents);
System.out.println("sending file..." + (current*100)/fileLength+"% complete!");
}
os.flush();
this.socket.close();
}catch(Exception e) {
e.printStackTrace();
}
}
Client receiving the file code:
System.out.println("Going to get the file...");
socket = new Socket(response.getIP().substring(1), response.getPort());
byte[] contents = new byte[10000];
FileOutputStream fos = new FileOutputStream("hank.txt");
BufferedOutputStream bos = new BufferedOutputStream(fos);
InputStream in = socket.getInputStream();
int bytesRead = 0;
System.out.println("Starting to read file...");
while((bytesRead = is.read(contents))!=-1) { //the error points to this lin
bos.write(contents,0,bytesRead);
}
bos.flush();
bos.close();
in.close();
//
socket.close();
Input stream for this socket is available in variable in
InputStream in = socket.getInputStream();
So
Change is.read(contents)) to in.read(contents))

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.

Invalid Stream Header - Socket Transfer in 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)
);

Able to send images over socket but not text files

My client can send Images normally to server, but when it comes to text files they arrive empty. Any ideas what am I doing wrong? I'd really appreciate help, because I have been trying to make this work for many days now. Thanks.
Here is the server code:
class TheServer {
public void setUp() throws IOException { // this method is called from Main class.
ServerSocket serverSocket = new ServerSocket(1991);
System.out.println("Server setup and listening...");
Socket connection = serverSocket.accept();
System.out.println("Client connect");
System.out.println("Socket is closed = " + serverSocket.isClosed());
BufferedReader rd = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String str = rd.readLine();
System.out.println("Recieved: " + str);
rd.close();
InputStream is = connection.getInputStream();
int bufferSize = connection.getReceiveBufferSize();
FileOutputStream fos = new FileOutputStream("C:/" + str);
BufferedOutputStream bos = new BufferedOutputStream(fos);
byte[] bytes = new byte[bufferSize];
int count;
while ((count = is.read(bytes)) > 0) {
bos.write(bytes, 0, count);
}
bos.flush();
bos.close();
is.close();
connection.close();
serverSocket.close();
}
}
and here is the client code:
public class TheClient {
public void send(File file) throws UnknownHostException, IOException { // this method is called from Main class.
Socket socket = null;
String host = "127.0.0.1";
socket = new Socket(host, 1991);
// Get the size of the file
long length = file.length();
if (length > Integer.MAX_VALUE) {
System.out.println("File is too large.");
}
BufferedWriter wr = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
wr.write(file.getName());
wr.newLine();
wr.flush();
byte[] bytes = new byte[(int) length];
FileInputStream fis = new FileInputStream(file);
BufferedInputStream bis = new BufferedInputStream(fis);
BufferedOutputStream out = new BufferedOutputStream(socket.getOutputStream());
int count;
while ((count = bis.read(bytes)) > 0) {
out.write(bytes, 0, count);
}
out.flush();
out.close();
fis.close();
bis.close();
socket.close();
}
}
You are prematurely closing BufferedReader on server side before reading all the data. This essentially closes the connection.
You should not use Reader or Writer for non-character streams like binary image data. And you should not mix BufferedReader with any other stream wrapper for the same stream since it may read as many data as it fills in buffer.

Categories