2

i'm working on an instant messaging project which it's client side is android and server is java
i need to use socket with streams
here is my protocol (something like HTTP) :

Method : attachment \n
Content-Length : {some-int-value} \n
\r\n
binary data bla bla bla...

lets assume i want to send this message from client to server
by doing so exchanging header section goes pretty well
but reading binary data at the server side never complete and server goes into hang for good

Client side code :

    Socket socket = new Socket();
    SocketAddress address = new InetSocketAddress(SERVER_ADDRESS, SERVER_PORT);
    try {
        socket.connect(address);
        InputStream in = socket.getInputStream();
        OutputStream out = socket.getOutputStream();
        BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
        BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
        byte[] data = getSomeBinaryData();
        writer.write("Method : attachment" + "\n");
        writer.write("Content-Length : " + data.length + "\n");
        writer.write("\r\n");
        writer.flush();
        out.write(data); // write binary data
        // do more exchange later
    } catch (IOException ex) {
        // handle exception
    }

Server starter code :

public static void main(String[] args){
    ExecutorService pool = Executors.newFixedThreadPool(50);
    try (ServerSocket server = new ServerSocket(PORT_NUMBER)) {
        while (true) {
            try {
                Socket connection = server.accept();
                Callable<Void> task = new ClientTask(connection);
                pool.submit(task);
            } catch (IOException ex) {}
        }
    } catch (IOException ex) {
        System.err.println("Couldn't start server");
    }
}

Server Task thread for each client :

class ClientTask implements Callable<Void> {

private Socket connection;
private HashMap<String, String> header = new HashMap<>();
private byte[] content;

ClientTask(Socket c) {
    this.connection = c;
}

@Override
public Void call() throws Exception {
    InputStream in = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
    readHeader(reader);
    System.out.println("incoming message : " + header.get("Method"));
    int contentLength = Integer.parseInt(header.get("Content-Length"));
    content = new byte[contentLength];
    int bytesRead = in.read(content, 0, contentLength);
    System.out.print(bytesRead);
    return null;
}

private void readHeader(BufferedReader reader){
    try {
        char c;
        StringBuilder builder = new StringBuilder();
        while ((c = (char) reader.read()) != '\r'){
            if(c == '\n'){
                String line = builder.toString();
                line = line.replaceAll(" ", "");
                String[] sections = line.split(":");
                header.put(sections[0], sections[1]);
                builder = new StringBuilder();  // clear builder
            }else {
                builder.append(c);
            }
        }
        reader.read();  // skip the last \n character after header
    } catch (IOException e) {
        e.printStackTrace();
    }
}
3
  • 1
    @JamesKPolk i'm writing header string with Writer and binary data with OutputStream Commented Jul 21, 2017 at 1:55
  • My bad, I don't know how I missed that. Ignore my previous comment. Commented Jul 21, 2017 at 12:40
  • 1
    The code in ClientTask.call() needs to loop until it receives the expected amount of data, or an EOF or socket exception. There is no guarantee that that in.read(content, 0, contentLength); will read contentLength bytes in one call. Commented Jul 21, 2017 at 12:46

1 Answer 1

2

As James said a clue I wanted to share the solution
maybe it help someone with similar issue
in the call method of ClientTask class i should use this code :

@Override
public Void call() throws Exception {
    InputStream in = connection.getInputStream();
    BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
    readHeader(reader);
    System.out.println("incoming message : " + header.get("Method"));

    // read binary Content
    int bytesRead = 0;
    int bytesToRead = Integer.parseInt(header.get("Content-Length"));
    content = new byte[bytesToRead];
    while (bytesRead < bytesToRead) {
        int result = in.read(content, bytesRead, bytesToRead - bytesRead);
        if (result == -1) 
            break; // end of stream
        bytesRead += result;
    }
    return null;
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.