1

I'm currently trying to implement an application to communicate with a machine, and it should essentially work as follows:

  • The program sends a message to the server (in this case, the first 255 bytes of a file).
  • The machine responds with a "message successfully received" or "error receiving message" response.
  • The program then has to decide whether to send the next message (next 255 bytes) or not (error on the last message, must start over) depending on the machine's response.
  • And so on for each message the program needs to send (depends on the size of the file).

So, we thought of having a thread to do the sending, and another to do the receiving, since we have an api to register a class as the one to receive messages from the machine (just by implementing an interface), and the methods to send messages to the machine are not of the blocking type, so a way to wait for the machine's response so the program can decide what to do after the response arrives is necessary.

So, we needed to synchronize these two threads somehow, since it's possible to determine how many messages they would exchange, which made us try a CyclicBarrier. This is the code for testing whether a CyclicBarrier would help us solve this problem (the program doesn't actually use sockets to communicate with the machine, this is just for testing the barrier):

import java.io.*;
import java.net.*;
import java.util.concurrent.*;

public class BlockingTest{
  private CyclicBarrier barrier;

  class Receiver implements Runnable{
    @Override public void run(){
      try{
        ServerSocket ss = new ServerSocket(8080);
        while(!barrier.isBroken()){
          System.out.println("Waiting message...");
          Socket response = ss.accept();
          BufferedReader br = new BufferedReader(new InputStreamReader(
              response.getInputStream()));
          System.out.printf("Received: %s\n", br.readLine());
          barrier.await();
        }
      }catch(InterruptedException | BrokenBarrierException |
        IOException ex){
        System.err.println(ex.getMessage());
      }
    }
  }

  public BlockingTest(){
    this.barrier = new CyclicBarrier(2, new Runnable(){
      @Override public void run(){
        System.out.println("done.");
      }
    });

    new Thread(new Receiver()).start();

    try{
      Socket sender = new Socket("localhost", 8080);
      PrintWriter pw = new PrintWriter(sender.getOutputStream(), true);
      for(int i = 0; i < 3; i++){
        System.out.println("Sending message:");
        pw.println("Message!");
        this.barrier.await();
      }
    }catch(InterruptedException | BrokenBarrierException | IOException ex){
      System.err.println(ex.getMessage());
    }
  }

  public static void main(String[] arg){
    new BlockingTest();
  }
}

This code works as expected if we only send one message (no for block in the BlockingTest() constructor, just send the message), but after adding the for block, it doesn't work as expected. It only works the first time, then it hangs:

Waiting message...
Sending message:
Received: Message!
done.
Waiting message...
Sending message:

The questions are:

  • How to make the barrier reusable? is that automatic or does it have to be done by hand?

  • Is the program hanging due to something i missed with the sockets (or the barrier code)?

Jose Ramirez
  • 381
  • 6
  • 20
  • Since sending and receiving are done sequentially, all the work can be done in single thread. Two threads are unnecessary complication and wasting of resources. – Alexei Kaigorodov Oct 12 '13 at 06:52
  • I thought so, but we had problems trying to make it sequential, since the object marked to receive the message is notified of the incoming message through a hardware interrupt, over which we have no control, and happens even faster than what it takes the program to wait for the machine's response, so sometimes it loses messages; something unacceptable in our case, since the files are actually operating systems for smart card chips. – Jose Ramirez Oct 12 '13 at 11:14
  • What hardware interrupts are you talking about? The text you showed uses only standard Socket and ServerSocket usage. Then, in the test, single barrier is used both for client and server threads. In reality, client and server run in different processes and cannot access the same object. – Alexei Kaigorodov Oct 12 '13 at 11:40
  • That's why I said i don't use them to talk to the machine, they were there to see how the barrier works; i thought they would be enough to make a simple handshaking scenario, and technically, the machine is not a server, all the program (sending/receiving threads) runs on a single computer; the machine only responds to what is sent to it in this/that way, depends on its internal protocol. – Jose Ramirez Oct 12 '13 at 11:49
  • The interrupt comes from the PCI card that is used to communicate with the machine, which is handled through a proprietary driver we can interact with through a java library. – Jose Ramirez Oct 12 '13 at 11:56

1 Answers1

0

The reason it hangs is that you're opening one connection to the server and keep sending data to it, but in the receiving end, you're discarding the first connection, and start waiting for the next connection to happen.

Either you can create a new connection from the sender every time you send data. The code block

Socket sender = new Socket("localhost", 8080);
PrintWriter pw = new PrintWriter(sender.getOutputStream(), true);

has to be moved inside the for loop. (of course, take care to release all resources)

OR,

fix the receiver to read data from the first connection, instead of waiting for a new connection for the second pack of data.

srkavin
  • 1,152
  • 7
  • 17
  • Nice... :) now it works (the program doesn't hang at all and is left waiting for a message). But what do you mean when you say "fix the receiver to read data from the first connection"? – Jose Ramirez Oct 12 '13 at 03:08
  • That is to move "Socket response = ss.accept(); BufferedReader br = new BufferedReader(new InputStreamReader(response.getInputStream()));" out of while loop, and keep reading next line of data from that connection. – srkavin Oct 12 '13 at 04:38