I am making a project, and part of it is about transporting an mp3 file from clients to the server using TCP. My idea is that the client will convert the mp3 to a byte array through FileInputStream and the Output Stream connected to the socket will deliver the byte array to the server. The server will get the byte array through Input Stream of the socket and make it convert it back to the mp3 file through FileOutputStream.

However, I have two problems. First, The program runs fine, but the final mp3 file the server converted is an empty file containing only 1 byte while the byte array received and used by the FileOutputStream is not empty. I know something must be wrong when my server is trying to convert the byte array back to mp3 because only using FileOutputStream seems too easy and I might have misunderstood its functionality, so I wish to know how to properly receive the byte array from the socket.

Secondly, I tried to compare the byte array in both the program, and I found out they are different. Part of them are the same, but most of them are different, especially the beginning and the end of the byte arrays, and I'm not sure why. Do I have a conceptual problem with how to use InputStream and OutputStream from the socket?

Here is part of the code for the client which sends out the mp3:

public static void sendPackets(){System.out.println("Sending test file...");try{while (active){File file = new File("Sorrow.mp3"); // Sorrow.mp3 is the local mp3 music needs to be sentFileInputStream loc = new FileInputStream(file);sendData = new byte[(int)file.length()];loc.read(sendData);//socket_tcp is a Socket object connecting to the serverOutputStream fis = socket_tcp.getOutputStream(); fis.write(sendData);fis.flush();fis.close();break;}} catch (IOException e) {e.printStackTrace();}}

And here is the code for the Server, which receives and convert the byte array back to mp3:

/** This is the function for the thread listening and receiving the music* active is a boolean value tracking whether the server is suppose to keep running or not**/public static void listen() {while (active) {try {//Wait until packet is received// listenSocket is a ServerSocket specific for this threadsocket = listenSocket.accept();System.out.println("We got music from the client!");File file = new File("Song.mp3");InputStream is = socket.getInputStream();receiveData = new byte[1024];is.read(receiveData);System.out.println(Arrays.toString(receiveData));FileOutputStream fos = new FileOutputStream(file);fos.write(receiveData);fos.flush();fos.close();} catch (IOException e) {if(active) {listen();} else {break;}}}

I am new to this community, so If I made any mistake in asking the question, please let me know, Thank you! Any help is appreciated!

1

Best Answer


I haven't tried to debug your exact problem, but I have some comments.

Your receiveData buffer is only 1K

Your receiveData buffer is only 1K. I imagine your MP3 is longer than that.

receiveData = new byte[1024];is.read(receiveData);

Experiment with streams in a simpler way first

Rather than sending the file over a socket, try writing some code to copy the file to another folder (i.e. from a FileInputStream to a FileOutputStream). Once you have got that working reliably, and you get the hang of streams, you can use the same code to write across a socket. The socket adds a lot of extra complexity—more moving parts—which makes things harder to debug.

The buffer is not strictly needed

Reading the file into a buffer before writing it to the output stream is a speed optimization. You could simplify the code—at least to start with—by reading from the InputStream and directly writing byte-by-byte to the OutputStream. Once you have got that simpler version working then you could introduce a buffer if you found it unperformant. In practice, using a buffer may not make much difference because operating systems do a lot of pre-emptive caching themselves.

read() should be in a loop

The read() methods on an InputStream return the total number of bytes read. There is no guarantee all the bytes will be read in one go. You should always put the read() in a loop and use the number returned as an offset into the array for the next read, until you get -1 to signal the end of the file.

byte[] buffer = new byte[bufferSize];int bytesRead = 0;while ((bytesRead = input.read(buffer)) != -1) {output.write(buffer, 0, bytesRead);}

Use try with resources

To ensure your resources are freed even when an exception is thrown, you should get in the habit of using a try..finally block or, even better, a try-with-resources block which calls close() for you.

Example:

FileOutputStream fos = new FileOutputStream(file);try {fos.write(receiveData);} finally {fos.close();}

Or the more concise equivalent with a try-with-resources block:

try (FileOutputStream fos = new FileOutputStream(file)) {fos.write(receiveData);}

No need for flush()

There's no need to flush() and close(). The latter automatically flushes before closing the stream.