Socket Communication: Thread hangs - java

I've got a simple socket server (it is for HL7 communication). When it runs longer in production, socket threads hang and consume a lot of CPU time.
This is the relevant code (shortened) for the listener thread:
public void run() {
try {
serverSocket = new ServerSocket(port, backlog, bindAddress);
serverSocket.setSoTimeout(timeout); // 1000 ms
do {
Socket socket = null;
try {
socket = serverSocket.accept();
} catch (SocketTimeoutException to) {
socket = null;
} catch (InterruptedIOException io) {
socket = null;
} catch (IOException e) {
logger.fatal("IO exception while socket accept", e);
socket = null;
}
try {
if (socket != null)
processConnection(socket);
} catch (RuntimeException e) {
logger.fatal("caught RuntimeException trying to terminate listener thread", e);
}
} while (running);
} catch (IOException e) {
logger.fatal("error binding server socket - listener thread stopped", e);
}
}
This code starts a new thread for processing an incoming connection:
protected void processConnection(Socket socket) {
Hl7RequestHandler requestHandler = createRequestHandler();
requestHandler.setSocket(socket);
requestHandler.start();
}
This is the code for the request handler thread (keepAlive is set to true):
public void run() {
try {
setName("Hl7RequestHandler-" + socket.getPort());
processRequest();
} catch (IOException e) {
logger.fatal("IO exception during socket communication", e);
}
}
public void processRequest()
throws IOException {
socket.setSoTimeout(socketTimeout); // 1000 ms
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
BufferedReader inputReader = new BufferedReader(new InputStreamReader(inputStream, encoding));
Writer outputWriter = new OutputStreamWriter(outputStream, encoding);
int timeouts = 0;
boolean failure = false;
do {
StringBuilder message = new StringBuilder();
try {
char c;
do {
c = (char)inputReader.read();
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && ((short)c) != -1);
} catch (SocketTimeoutException te) {
timeouts++;
if(!keepAlive && timeouts >= 3 ) {
socket.close();
return;
}
}
String messageStr = message.toString();
if (messageStr.length() == 0)
continue;
failure = !processMessage(messageStr, outputWriter);
outputWriter.flush();
outputStream.flush();
// nächste Runde?
if (!keepAlive || failure)
socket.close();
} while (keepAlive && !failure);
}
When I test this locally, it works well.
But in production, there are multiple request handler threads that "hang". "Keep Alive" is ment to hold open the connection waiting for more messages. (To avoid opening up new connections all the time.) I assume inputReader.read() returns -1 after the timeout of 1s, which results in calling the method just again. Why does this eat up all the CPU time?
Have you got any advice?
Thanks in advance,
Matthias

One thing I can see straight off is this :
char c;
do {
c = (char)inputReader.read();
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && ((short)c) != -1);
is the cast of the inputReader.read() to char. BufferedReader.read() returns an int, a signed value. You cast it to char that is an unsigned value, discarding the negative sign if there is one, a narrowing conversion. Then converting to short is not bringing back the negative sign if there was one.
Try rewriting as :
char c;
int val;
do {
val = inputReader.read();
// do this if you want, you don't have to
c = (char) val;
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && val != -1);
I've taken another look at your loop and I'm confused.
char c;
do {
c = (char)inputReader.read();
if ((c == CARRIAGE_RETURN || c == START_OF_MESSAGE) &&
message.length() == 0)
else if (c != END_OF_MESSAGE && ((short)c) != -1)
// ein Byte "Nutzlast"
message.append(c);
} while (c != END_OF_MESSAGE && ((short)c) != -1);
The logic of your if statements are confusing (to me at least).
You have no statements for the first if clause, not even an empty statement.
You have to have either {} or a ; Does your code compile?

Related

BufferedReader.readLine() pauses my application?

I am using this code:
while (true) {
sendData("hi");
System.out.println("Data sent!");
BufferedReader inFromServer;
try {
inFromServer = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
} catch (IOException e1) {
inFromServer = null;
e1.printStackTrace();
}
System.out.println("Recieved!"); //I see this de-bug message.
try {
modifiedSentence = inFromServer.readLine();
System.out.println("FROM SERVER: " + modifiedSentence); //I do NOT see this de-bug message!
} catch (IOException e) {
e.printStackTrace();
}
}
It successfully sends data to a server - And the server successfully sends data back:
public void run () {
//handle the session using the socket (example)
try {
sendData("Hi");
System.out.println("Data sent!"); //I see this de-bug message.
} catch (Exception e) {
e.printStackTrace();
}
}
However for some reason, the application seems to pause at the inFromServer.readLine() method. I see the "Recieved!" de-bug message, but not the "FROM SERVER" de-bug message.
There are no errors at all. It just seems to hang there.
Why is it hanging, and how can I fix that?
Well this simply means that inFromServer does not receive any line.
Make sure you really send a line,
Reads a line of text. A line is considered to be terminated by any one
of a line feed ('\n'), a carriage return ('\r'), or a carriage return
followed immediately by a linefeed.
Have a look at the readLine method :
String readLine(boolean ignoreLF) throws IOException {
StringBuffer s = null;
int startChar;
synchronized (lock) {
ensureOpen();
boolean omitLF = ignoreLF || skipLF;
bufferLoop:
for (;;) {
if (nextChar >= nChars)
fill();
if (nextChar >= nChars) { /* EOF */
if (s != null && s.length() > 0)
return s.toString();
else
return null;
}
boolean eol = false;
char c = 0;
int i;
/* Skip a leftover '\n', if necessary */
if (omitLF && (cb[nextChar] == '\n'))
nextChar++;
skipLF = false;
omitLF = false;
charLoop:
for (i = nextChar; i < nChars; i++) {
c = cb[i];
if ((c == '\n') || (c == '\r')) {
eol = true;
break charLoop;
}
}
startChar = nextChar;
nextChar = i;
if (eol) {
String str;
if (s == null) {
str = new String(cb, startChar, i - startChar);
} else {
s.append(cb, startChar, i - startChar);
str = s.toString();
}
nextChar++;
if (c == '\r') {
skipLF = true;
}
return str;
}
if (s == null)
s = new StringBuffer(defaultExpectedLineLength);
s.append(cb, startChar, i - startChar);
}
}
}
Note that this one receive a boolean, but calling readLine simply call this one with false passed, unless on Linux.
Notice the for(;;) loop, which is an infinite loop.
Try concatening to the "line" sent from the server
System.getProperty("line.separator");

FileInputStream returns null

I have two methods, both using FileInputStream Objects.
The First one returns expected value. This method works fine.
But the Second method returns nothing. The value passed to the second method is not null.
I need to get the hexadecimal format of the files passed to methods.
Why is it so? Kindly Explain.
Here is my code
public String binaryFile1(File file1){
try{
stringBuilder1=new StringBuilder();
is1=new FileInputStream(file1);
while(b!=-1){
counter++;
b=is1.read();
String s = Integer.toHexString(b).toUpperCase();
if (s.length() == 1) {
stringBuilder1.append('0');
}
if(counter%5==0){
stringBuilder1.append(s).append("\n");
counter=0;
}else
stringBuilder1.append(s).append(' ');
}
is1.close();
}catch(Exception e){
e.printStackTrace();
}
return stringBuilder1.toString();
}
public String binaryFile2(File file2){
try{
stringBuilder2=new StringBuilder();
is2=new FileInputStream(file2);
while(b!=-1){
counter++;
b=is2.read(); //Here b does not get any content assigned.
String s = Integer.toHexString(b).toUpperCase();
if (s.length() == 1) {
stringBuilder2.append('0');
}
if(counter%5==0){
stringBuilder2.append(s).append("\n");
counter=0;
}else
stringBuilder2.append(s).append(' ');
}
is2.close();
}catch(Exception e){
e.printStackTrace();
}
return stringBuilder2.toString(); //Here stringBuilder2 is null
}
Since b is shared and you don't reset it after binaryFile1 it's still -1 at the start of binaryFile2. I suggest you use,
int b;
while ((b = is2.read()) != -1) {
// ...
}
Edit
It is important to close your resources when you're done. I also suggest you try and limit variable scope as much as possible. Using try-with-resources you could write binaryFile2 like
public String binaryFile2(File file) {
StringBuilder sb = new StringBuilder();
int counter = 0;
try (InputStream is = new FileInputStream(file)) {
int b;
while ((b = is.read()) != -1) {
counter++;
String s = Integer.toHexString(b).toUpperCase();
if (s.length() == 1) {
sb.append('0');
}
sb.append(s);
if (counter % 5 == 0) {
sb.append(System.lineSeparator());
counter = 0;
} else {
sb.append(' ');
}
}
} catch (Exception e) {
e.printStackTrace();
}
return sb.toString();
}

java thread waiting for input on comport blocks other thread as well

I've got a main program that starts two threads. First I only had this thread, that executes the following inside the while(true):
loopCounter++;
outputStream.write(pollBuf);
readResponse();
Thread.sleep(200);
outputStream.write(statusBuf);
readResponse();
logger.info("status executed");
The problem is that when the second readResponse doesn't return because the device listening to the comport simply doesn't answer I'm stuck and the display that gives the status of the machine simply still shows "running" instead of software error or something alike.
So I need to know when this thread is stuck and therefore I added another thread that now gets created and started in the main program right before the other thread, the code inside the while(true) of the run() method of this second thread:
public class StatusThread implements Runnable {
static Logger logger = Logger.getLogger(StatusThread.class);
private Nv10ToVcdm mainProgram;
public void initialize(Nv10ToVcdm mProgram, boolean acceptBills) {
mainProgram = mProgram;
}
public void run() {
int loopCounter = mainProgram.getLoopCounter();
while (true) {
try {
Thread.sleep(1000);
int currentLoopCounter = mainProgram.getLoopCounter();
if (loopCounter != currentLoopCounter) {
loopCounter = currentLoopCounter;
} else {
mainProgram.writeToDisplay("SOFTWARE", "ERROR");
}
} catch (InterruptedException ie) {
logger.error("Interrupted exception: " + ie.getMessage());
mainProgram.errorOnDisplay();
}
}
}
}
Sadly the first thread being stuck on listening to the comport doesn't release the claim it has on the cpu so the second thread doesn't get any CPU time. So: How to show an error on the display when the thread listening to a com port hangs?
The readResponse method that hangs, afaik it hangs on "byte firstByte = (byte) inputStream.read();" because there's nothing to read:
private void readResponse() {
byte[] bufferLeft = new byte[4];
byte[] bufferRight = new byte[2];
byte size = 0;
boolean responseFound = false;
try {
while(!responseFound) {
byte firstByte = (byte) inputStream.read();
if (firstByte == -1) {
logger.error("first byte of response is -1");
mainProgram.errorOnDisplay();
break;
}
for (int i = 0; i < 4; i++) {
bufferLeft[i] = (byte) inputStream.read();
}
size = bufferLeft[0];
if (size > 0) {
bufferRight = new byte[size];
int i2 = 0;
while (i2 < size) {
bufferRight[i2] = (byte) inputStream.read();
i2++;
}
}
if (firstByte == 1 && bufferLeft[1] == 40) {
responseFound = true;
}
}
if (size == 11) {
// some code
}
} catch(IOException ioe) {
logger.error("IO Exception in readResponse: " + ioe.getMessage());
mainProgram.errorOnDisplay();
}
}
Edit (added complete code for second thread & readResponse method)
Inputstream is initialized as follows:
serialPort = (SerialPort) commPort;
serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
inputStream = serialPort.getInputStream();
Did you tried to cheack data availability before read?
Something like:
if (inputStream.available() > 0) {
// do your read
} else {
// wait for some time and retry or trow an error
}

Trouble receiving data to Java socket client from C socket server

I'm having a problem trying to send strings back and forth between a simple Java socket client and a simple C socket server.
It works as follows:
Java client sends msg to C server
out.writeBytes(msg);
C server receives the msg and puts into buf
if ((numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
C server sends the messsage back to the Java client
if ((len = send(new_fd, buf, numbytes, 0)) == -1)
perror("send");
However the Java client cannot receive the msg from the C server, I've tried using DataInputStream, BufferedReader, reading into char[], byte[], converting to string but cannot get the received message. When trying to read into an array on the client side I sometimes get only the first character which leads me to believe it's a blocking problem?
Any help would be appreciated
Code:
C server main loop
while(1) { // main accept() loop
sin_size = sizeof their_addr;
new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size);
if (new_fd == -1) {
perror("accept");
continue;
}
inet_ntop(their_addr.ss_family,
get_in_addr((struct sockaddr *)&their_addr),
s, sizeof s);
printf("server: got connection from %s\n", s);
if ((numbytes = recv(new_fd, buf, MAXDATASIZE-1, 0)) == -1) {
perror("recv");
exit(1);
}
buf[numbytes] = '\0';
printf("msg size: '%d' bytes\n",numbytes);
printf("received msg: %s\n",buf);
char* array = (char*)buf;
printf("as char array: %s\n", array);
if (!fork()) { // this is the child process
close(sockfd); // child doesn't need the listener
int len = 0;
if ((len = send(new_fd, buf, numbytes, 0)) == -1)
perror("send");
printf("sent %d bytes\n", len);
close(new_fd);
exit(0);
}
close(new_fd); // parent doesn't need this
}
Java client
public void send(String text){
Socket sock = null;
DataInputStream in = null;
DataOutputStream out = null;
BufferedReader inReader = null;
try {
sock = new Socket(HOST, PORT);
System.out.println("Connected");
in = new DataInputStream(sock.getInputStream());
out = new DataOutputStream(sock.getOutputStream());
out.writeBytes(text + "\n");
String res = "";
//get msg from c server and store into res
System.out.println("Response: " + res);
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
sock.close();
//in.close();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Knowing How to Detect a Disconnection when Reading Socket Data (InputStream)

I have a thread that is constantly reading data from an InputStream. The InputStream data is coming from a Bluetooth socket. Previously, I wasn't using the if(mmInStream.available() > 0) around the InputStream read statement and when the bluetooth socket went away (someone turned off the device), the mmInStream.read would throw a IOException and then I could process my disconnection logic. What is the best way to determine when a disconnect has occurred?
First byte of 0xEE tells me its the leader of the data packet and the second tells me the length to read.
public void run() {
byte[] tempBuffer = new byte[1024];
byte[] buffer = null;
int byteRead=0;
long timeout=0;
long wait=100;
while (true) {
try {
timeout = System.currentTimeMillis() + wait;
if(mmInStream.available() > 0) {
while((mmInStream.available() > 0) && (tempBuffer[0] != (byte) 0xEE) && (System.currentTimeMillis() < timeout)){
byteRead = mmInStream.read(tempBuffer, 0, 1);
}
if(tempBuffer[0] == (byte) 0xEE){
timeout = System.currentTimeMillis() + wait;
while(byteRead<2 && (System.currentTimeMillis() < timeout)){
byteRead += mmInStream.read(tempBuffer, 1, 1);
}
}
timeout = System.currentTimeMillis() + wait;
while((byteRead<tempBuffer[1]) && (System.currentTimeMillis() < timeout)){
byteRead += mmInStream.read(tempBuffer, byteRead, tempBuffer[1]-byteRead);
}
}
if(byteRead > 0){
//do something with the bytes read in
}
}
catch (IOException e) {
bluetoothConnectionLost();
break;
}
}
}
You don't need all this malarkey with available(). Just set a read timeout with setSoTimeout, read, detect read returning -1, use the count returned by read if > 0 rather than assuming the buffer got filled, catch SocketTimeoutException to detect read timeouts, and catch IOException to detect other breakages.
After a look at the documentation, I think it's like this:
public void run() {
byte[] tempBuffer = new byte[1024];
int byteRead = 0;
while (true) {
try {
bytesRead = mmInStream.read(tempBuffer, 0, tempBuffer.length);
if (bytesRead < 0)
// End of stream.
break;
// Do something with the bytes read in. There are bytesRead bytes in tempBuffer.
} catch (IOException e) {
bluetoothConnectionLost();
break;
}
}
}
I think it's like this:
void fun(){
isOpen = true;
try{
InputStream stream = socket.getInputStream();
while(isOpen){
byte[] buf = new byte[8];
int pos = stream.read(buf);
if (pos < 0) {
throw new IOException();
}
//dosomething...
}
}catch(IOException e) {
isOpen = false;
}finally{
//do dispose here
}
}

Categories

Resources