Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice for reading / writing to a java server socket

How do you design a read and write loop which operates on a single socket (which supports parallel read and write operations)? Do I have to use multiple threads? Is my (java) solution any good? What about that sleep command? How do you use that within such a loop?

I'm trying to use 2 Threads:

Read

public void run() {
    InputStream           clientInput;
    ByteArrayOutputStream byteBuffer;
    BufferedInputStream   bufferedInputStream;
    byte[]                data;
    String                dataString;
    int                   lastByte;

    try {
        clientInput         = clientSocket.getInputStream();
        byteBuffer          = new ByteArrayOutputStream();
        bufferedInputStream = new BufferedInputStream(clientInput);

        while(isRunning) {  

            while ((lastByte = bufferedInputStream.read()) > 0) {
                byteBuffer.write(lastByte);
            }
                data       = byteBuffer.toByteArray();  
                dataString = new String(data);
                byteBuffer.reset();     
        }   

    } catch (IOException e) {
        e.printStackTrace();
    }
}

Write

public void run() {
    OutputStream clientOutput;
    byte[]       data;
    String       dataString;

    try {
        clientOutput = clientSocket.getOutputStream();

        while(isOpen) { 

            if(!commandQueue.isEmpty()) {
                dataString = commandQueue.poll();
                data       = dataString.getBytes();
                clientOutput.write(data);
            }                   
            Thread.sleep(1000);
        }       
        clientOutput.close();           
    } 
    catch (IOException e) {
        e.printStackTrace();
    } 
    catch (InterruptedException e) {
        e.printStackTrace();
    }
}

Read fails to deliver a proper result, since there is no -1 sent. How do I solve this issue?

Is this sleep / write loop a good solution?

like image 754
Schifty Avatar asked Apr 25 '12 08:04

Schifty


1 Answers

There are basically three ways to do network I/O:

  1. Blocking. In this mode reads and writes will block until they can be fulfilled, so if you want to do both simultaneously you need separate threads for each.

  2. Non-blocking. In this mode reads and writes will return zero (Java) or in some languages (C) a status indication (return == -1, errno=EAGAIN/EWOULDBLOCK) when they cannot be fulfilled, so you don't need separate threads, but you do need a third API that tells you when the operations can be fulfilled. This is the purpose of the select() API.

  3. Asynchronous I/O, in which you schedule the transfer and are given back some kind of a handle via which you can interrogate the status of the transfer, or, in more advanced APIs, a callback.

You should certainly never use the while (in.available() > 0)/sleep() style you are using here. InputStream.available() has few correct uses and this isn't one of them, and the sleep is literally a waste of time. The data can arrive within the sleep time, and a normal read() would wake up immediately.

like image 97
user207421 Avatar answered Nov 15 '22 09:11

user207421