• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3437
  • Last Modified:

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

0
jimmyraywv
Asked:
jimmyraywv
  • 6
  • 4
  • 4
  • +2
2 Solutions
 
CEHJCommented:
>> 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
0
 
objectsCommented:
>            out.write(

use println() instead of write
0
 
kurian2z5Commented:
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.
0
Free Tool: Path Explorer

An intuitive utility to help find the CSS path to UI elements on a webpage. These paths are used frequently in a variety of front-end development and QA automation tasks.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 
mukundha_expertCommented:
>> 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.


0
 
CEHJCommented:
>>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
0
 
mukundha_expertCommented:
but it will return only after a CR or LF or both or EOF(in which case returns null) right?
0
 
CEHJCommented:
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
0
 
mukundha_expertCommented:
oh.. yes.. in this case this is true. thank you.
0
 
jimmyraywvAuthor Commented:
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.
0
 
CEHJCommented:
>>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?
0
 
jimmyraywvAuthor Commented:
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?
0
 
jimmyraywvAuthor Commented:
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

0
 
CEHJCommented:
The server expects the client to write first. *It* will then block waiting for more input
0
 
objectsCommented:
> Even though my testing did not indicate the need

it is needed, readLine() reads until eol. you weren't writing one.

>                   while ((line = in.readLine()) != null) {

readFromSocket() will never return as readLine() will not return null until eof is reached. Thats not going to happen until you close the stream

You either need seperate threads reading and writing to the socket.
Or define a protocol for the server and client to follow. eg. client sends a line, server responds with a line. You can then change your logic to follow that protocol.
0
 
jimmyraywvAuthor Commented:
>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

0
 
objectsCommented:
> 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 :)
0
 
objectsCommented:
> 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 :)
0
 
CEHJCommented:
:-)
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

Join & Write a Comment

Featured Post

Get expert help—faster!

Need expert help—fast? Use the Help Bell for personalized assistance getting answers to your important questions.

  • 6
  • 4
  • 4
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now