Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to send both binary file and text using the same socket

i have to send a short string as text from client to server and then after that send a binary file.

how would I send both binary file and the string using the same socket connection?

the server is a java desktop application and the client is an Android tablet. i have already set it up to send text messages between the client and server in both directions. i have not yet done the binary file sending part.

one idea is to set up two separate servers running at the same time. I think this is possible if i use two different port numbers and set up the servers on two different threads in the application. and i would have to set up two concurrent clients running on two services in the Android app.

the other idea is to somehow use an if else statement to determine which of the two types of files is being sent, either text of binary, and use the appropriate method to receive the file for the file type being sent.

example code for sending text

 PrintWriter out;
 BufferedReader in;

out = new PrintWriter(new BufferedWriter
(new OutputStreamWriter(Socket.getOutputStream())) true,);
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

out.println("test out");
String message = in.readLine();

example code for sending binary file

 BufferedOutputStream out;
 BufferedInputStream in;
 byte[] buffer = new byte[];
 int length = 0;

 out = new BufferedOutputStream(new FileOutputStream("test.pdf));
 in = new BufferedInputStream(new FileOutputStream("replacement.pdf"));

 while((length = in.read(buffer)) > 0 ){
 out.write(buffer, 0, length);
 }
like image 898
Kevik Avatar asked Sep 06 '13 07:09

Kevik


1 Answers

I don't think using two threads would be necessary in your case. Simply use the socket's InputStream and OutputStream in order to send binary data after you have sent your text messages.

Server Code

OutputStream stream = socket.getOutputStream();
PrintWriter out = new PrintWriter(
    new BufferedWriter(
        new OutputStreamWriter(stream)
    )
);
out.println("test output");
out.flush(); // ensure that the string is not buffered by the BufferedWriter

byte[] data = getBinaryDataSomehow();
stream.write(data);

Client Code

InputStream stream = socket.getInputStream();
String message = readLineFrom(stream);

int dataSize = getSizeOfBinaryDataSomehow();
int totalBytesRead = 0;
byte[] data = new byte[dataSize];

while (totalBytesRead < dataSize) {
    int bytesRemaining = dataSize - totalBytesRead;
    int bytesRead = stream.read(data, totalBytesRead, bytesRemaining);

    if (bytesRead == -1) {
        return; // socket has been closed
    }

    totalBytesRead += bytesRead;
}

In order to determine the correct dataSize on the client side you have to transmit the size of the binary block somehow. You could send it as a String right before out.flush() in the Server Code or make it part of your binary data. In the latter case the first four or eight bytes could hold the actual length of the binary data in bytes.

Hope this helps.


Edit

As @EJP correctly pointed out, using a BufferedReader on the client side will probably result in corrupted or missing binary data because the BufferedReader "steals" some bytes from the binary data to fill its buffer. Instead you should read the string data yourself and either look for a delimiter or have the length of the string data transmitted by some other means.

/* Reads all bytes from the specified stream until it finds a line feed character (\n).
 * For simplicity's sake I'm reading one character at a time.
 * It might be better to use a PushbackInputStream, read more bytes at
 * once, and push the surplus bytes back into the stream...
 */
private static String readLineFrom(InputStream stream) throws IOException {
    InputStreamReader reader = new InputStreamReader(stream);
    StringBuffer buffer = new StringBuffer();

    for (int character = reader.read(); character != -1; character = reader.read()) {
        if (character == '\n')
            break;
        buffer.append((char)character);
    }

    return buffer.toString();
}
like image 99
PoByBolek Avatar answered Nov 08 '22 13:11

PoByBolek