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;
}
}
> out.write(
use println() instead of 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(millis econds). It will block and if no data is received within the timeout, it will throw SocketTimeoutException and you can continue excecuting remaining code.
You can use socket.setSoTimeout(millis
>> 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.
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
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.
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?
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?
ASKER
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?
ASKER
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;
}
}
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
>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.
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();
}
}
> 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 :)
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 :)
which is what I suggested. Glad it worked for you :)
:-)
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