Link to home
Start Free TrialLog in
Avatar of jimmyraywv
jimmyraywv

asked on

Java Socket client hangs (blocks) when reading from server

Given the attached server and client code:  in ClientWorker.java, if I uncomment line21:  this.readFromSocket(), the client locks up and will not read.  It acts as though the client is blocking.  It has been a long time since I have tried to write Java sockets.  I was hoping I was doing something stupid and someone could help point that out.  What is causing this lock-up or blocking?
/*Socket Server Thread*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ClientWorker implements Runnable {
	private Socket socket;

	public ClientWorker(Socket socket) {
		this.socket = socket;
	}

	/**
	 * Run method of Runnable interface, does all the work.
	 */
	public void run() {
		try {
			//this.readFromSocket();
			this.writeToSocket();
		} catch (Throwable t) {
			t.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void readFromSocket() throws Throwable {
		BufferedReader in = null;
		String[] data = null;

		// Read data from socket
		in = new BufferedReader(new InputStreamReader(this.socket
				.getInputStream()));

		StringBuilder builder = new StringBuilder();
		String line = null;
		while ((line = in.readLine()) != null) {
			builder.append(line);
		}

		System.out.println(builder);
		data = builder.toString().split("::");
		for (String string : data) {
			System.out.println(string);
		}
	}

	private void writeToSocket() throws Throwable {
		PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true);
		out.write("READ_ME");
		out.flush();
		System.out.println("WROTE");
	}
}

/*Socket Client*/
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

public class SocketClient {
	private static Socket socket;

	public static void main(String[] args) throws Throwable {
		socket = new Socket(InetAddress.getLocalHost().getCanonicalHostName(),
				8080);

		write();
		read();

		closeConnections();
	}

	private static void write() throws Throwable {
		PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
		out.write("INVOICE::QUOTATION");
		System.out.println("WROTE");
	}

	private static void read() throws Throwable {

		BufferedReader in = null;
		in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

		System.out.println("READING");
		String line = null;
		StringBuilder builder = new StringBuilder();
		while ((line = in.readLine()) != null) {
			System.out.println("READING_LINE");
			builder.append(line);
		}
		System.out.println("RETURNED=" + builder);
	}

	private static void closeConnections() throws IOException {
		socket.close();
		socket = null;
	}
}

Open in new window

Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

>> What is causing this lock-up or blocking?

Blocking will occur if there' s nothing yet ready to be read. Make sure you're only attempting to read when you know something's being written
>            out.write(

use println() instead of write
When using read() the it will block until there is incoming data on the socket.

You can use socket.setSoTimeout(milliseconds). It will block and if no data is received within the timeout, it will throw SocketTimeoutException and you can continue excecuting remaining code.
Avatar of mukundha_expert
mukundha_expert

>> What is causing this lock-up or blocking?
firstly you need ensure CEHJ's comment, if thats correct then may be this reason

readLine() expects a "\r\n" at the end to recognize a line,

hence you need to use println() as suggested by objects.


>>readLine() expects a "\r\n" at the end to recognize a line,

Actually that's not the case. readLine will read whatever's in the buffer, irrespective of linefeed issues
but it will return only after a CR or LF or both or EOF(in which case returns null) right?
In this case, EOF would be end of buffer and it would return, as i said, what's in the buffer. You should be able to verify that by reading a file with no CR/LF anywhere
oh.. yes.. in this case this is true. thank you.
Avatar of jimmyraywv

ASKER

Even though my testing did not indicate the need, I changed my write to println whether i am writing to the socket from the client or the server.  However, I get the same results.  If I try to read from the inbound socket, it blocks and I can never finish the read on the server and get my results from the server to the client.  The client is blocking and I still have not figured out why.
>>I changed my write to println whether i am writing to the socket from the client or the server.

Yes, that will be a good idea although is probably not much to do with your problem.

Please post the server code if you can. Is it publicly accessible?
I added logic to the ClientWorker and the SocketClient to check to see if the input BufferedReader was ready().  It seems that if I try to read from both sides, BufferedReader is not ready on the second read.  Any ideas?
Here is the code...as of now.
public class ServerStarter {
	private static int PORT = 8080;
	private static int MAX_CONNECTIONS = 10;
	private static int NUMBER_XACTIONS = 100;

	public static void main(String[] args) {
		try {
			if (args.length >= 3) {
				try {
					PORT = Integer.valueOf(args[0]).intValue();
					MAX_CONNECTIONS = Integer.valueOf(args[1]).intValue();
					NUMBER_XACTIONS = Integer.valueOf(args[2]).intValue();
				} catch (Exception ignore) {
					// Ignore, keep default values
					System.err
							.println("WARNING::Server started with default settings.");
				}
			}

			System.out.println("Starting Server::PORT=" + PORT
					+ ", MAX_CONNECTIONS=" + MAX_CONNECTIONS
					+ ", NUMBER_XACTIONS=" + NUMBER_XACTIONS);

			// Start thread pool server
			Server server = new Server(PORT, MAX_CONNECTIONS, NUMBER_XACTIONS);
			new Thread(server).start();
		} catch (Throwable t) {
			System.out.println(t.getMessage());
			t.printStackTrace();
		}
	}
}

import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.om.tax.util.SimpleConsoleLogger;

public class Server implements Runnable {
	SimpleConsoleLogger logger = null;
	private boolean shutdown;
	private int port;
	private ExecutorService pool;

	/**
	 * Constructor
	 * 
	 * @param port
	 * @param size
	 * @param times
	 */
	public Server(int port, int size, int times) {
		// Port
		this.port = port;
		// need to match fixed pull size to ServerManager/ServiceContainer count
		this.pool = Executors.newFixedThreadPool(size);

	}

	/**
	 * Runnable run method, does all the work by listening on socket port.
	 */
	public void run() {
		try {
			// Get Logger instance
			logger = SimpleConsoleLogger.getInstance();

			// Get instance of ServiceManager
			// ServiceManager.getInstance();

			// Listen for socket connections
			this.listen();

		} catch (Throwable t) {
			t.printStackTrace();
		} finally {
			this.pool.shutdown();
		}
	}

	/**
	 * Listens for client connections over a socket. A thread is created for
	 * each connection.
	 */
	public void listen() {
		try {
			ServerSocket serverSocket = new ServerSocket(this.port);
			serverSocket.setSoTimeout(0);

			while (shutdown == false) {
				Socket socket = serverSocket.accept();
				ClientWorker worker = new ClientWorker(socket);
				this.pool.execute(worker);
			}
		} catch (Throwable t) {
			t.printStackTrace();
		}
	}

	/**
	 * Getter
	 * 
	 * @return
	 */
	private synchronized boolean isShutdown() {
		return this.shutdown;
	}

	/**
	 * Stops thread pool server.
	 */
	public synchronized void setShutdown() {
		this.shutdown = true;
	}

}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

public class ClientWorker implements Runnable {
	private Socket socket;

	public ClientWorker(Socket socket) {
		this.socket = socket;
	}

	/**
	 * Run method of Runnable interface, does all the work.
	 */
	public void run() {
		try {
			this.readFromSocket();
			this.writeToSocket();
		} catch (Throwable t) {
			t.printStackTrace();
		} finally {
			try {
				socket.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private void readFromSocket() throws Throwable {
		BufferedReader in = null;
		String[] data = null;

		// Read data from socket
		in = new BufferedReader(new InputStreamReader(this.socket
				.getInputStream()));

		StringBuilder builder = new StringBuilder();
		String line = null;
		if (in.ready()) {
			while ((line = in.readLine()) != null) {
				builder.append(line);
			}

			System.out.println(builder);
			data = builder.toString().split("::");
			for (String string : data) {
				System.out.println(string);
			}
		}

	}

	private void writeToSocket() throws Throwable {
		PrintWriter out = new PrintWriter(this.socket.getOutputStream(), true);
		out.println("READ_ME");
		System.out.println("WROTE");
	}
}

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.Socket;

public class SocketClient {
	private static Socket socket;

	public static void main(String[] args) throws Throwable {
		socket = new Socket(InetAddress.getLocalHost().getCanonicalHostName(),
				8080);

		write();
		read();

		closeConnections();
	}

	private static void write() throws Throwable {
		PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
		out.println("INVOICE::QUOTATION");
		System.out.println("WROTE");
	}

	private static void read() throws Throwable {

		BufferedReader in = null;
		in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

		System.out.println("READING");
		String line = null;
		StringBuilder builder = new StringBuilder();
		while (!in.ready()) {
			System.out.println("NOT_READY");
			Thread.sleep(500);
		}
		while ((line = in.readLine()) != null) {
			System.out.println("READING_LINE");
			builder.append(line);
		}
		System.out.println("RETURNED=" + builder);
	}

	private static void closeConnections() throws IOException {
		socket.close();
		socket = null;
	}
}

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of CEHJ
CEHJ
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>it is needed, readLine() reads until eol. you weren't writing one.

Perhaps i was not, but when I did, it did not change the observable behavior.  When I changed my write code to shutdown the output stream, I was able to get more reliable behavior.

Thanks for our help.
private static void write() throws Throwable {
		socket.getOutputStream().flush();
		PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
		out.println("INVOICE::QUOTATION");
		out.flush();
		System.out.println("WROTE_CLIENT_DATA");
		if (!socket.isOutputShutdown()) {
			System.out.println("SHUTTING_DOWN_CLIENT_OUTPUT");
			socket.shutdownOutput();
		}
	}

Open in new window

> Perhaps i was not, but when I did, it did not change the observable behavior.

thats because it wasn't the only problem as I mentioned in my comment above
and you client *does* write first already :)
> When I changed my write code to shutdown the output stream, I was able to get more reliable behavior.

which is what I suggested. Glad it worked for you :)
:-)