Omar Kooheji
Omar Kooheji

Reputation: 55790

Forwarding incoming TCP "Commands" to a function?

In Java, how would you set up a socket listener that listened to a socket for a series of bytes that represented a command and on recieving called a method which parsed the incoming data and invoked the appropriate command?

Clarification:

My issue is not with handling the commands (Which might also be error codes or responses to commands from the server) but with creating the socket and listening to it.

More Clarification:

What I want to do is mimic the following line of .Net (C#) code:

_stream.BeginRead(_data,0, _data.Length, new  
    AsyncCallback(this.StreamEventHandler), _stream);

Where:

I am rewriting a library from C# into Java and the component I am currently writing passes commands to a server over TCPIP but also has to be able to bubble up events/responses to the layer above it.

In C# this seems to be trivial and it's looking less and less so in Java.

Upvotes: 3

Views: 710

Answers (8)

Mario Ortegón
Mario Ortegón

Reputation: 18900

Starting from my other answer: The specific part you request is the one that goes into the section: "Magic goes here". It can be done in ohh so many ways, but one is:

final InputStream in = socket.getInputStream();
// This creates a new thread to service the request.
new Thread(new Runnable(){
  public void run(){
    byte[] retrievedData= new byte[ITEM_LENGTH];
    in.read(retrievedData, 0, ITEM_LENGTH);
    in.close();

    // Here call your delegate or something to process the data
    callSomethingWithTheData(retrievedData);
  }
}).start();

Upvotes: 1

Peter Lawrey
Peter Lawrey

Reputation: 533820

You could create an enum with one member per command

interface Comamnd {
    // whatever you expect all command to know to perform their function
    void perform(Context context);
}

enum Commands implements Command{
   ACTIONONE() {
        void perform(Context context) {
             System.out.println("Action One");
        }
   },
   ACTIONTWO() {
        void perform(Context context) {
             System.out.println("Action Two");
        }
   }
}

// initialise
DataInputStream in = new DataInputStream(socket.getInputStream());

// in a loop
byte[] retrievedData= new byte[ITEM_LENGTH];
in.readFully(retrievedData);
String command = new String(retrievedData, 0);
Commands.valueOf(command).perform(context);

Upvotes: 0

Mario Ortegón
Mario Ortegón

Reputation: 18900

To create an listen to a socket, in a very naive way:

    mServerSocket = new ServerSocket(port);

    listening = true;

    while (listening) {

      // This call blocks until a connection is made
      Socket socket = serverSocket.accept();

      OutputStream out = socket.getOutputStream();
      InputStream in = socket.getInputStream();

      // Here you do your magic, reading and writing what you need from the streams
      // You would set listening to true if you have some command to close the server
      // remotely

      out.close();
      in.close();
      socket.close();
   }

Normally it is a good idea to delegate the processing of the input stream to some other thread, so you can answer the next request. Otherwise, you will answer all requests serially.

You also need to define some kind of protocol of what bytes you expect on the input and output streams, but from your question it looks like you already have one.

Upvotes: 0

Any naive approach most likely will not scale well.

Consider using a REST-approach with a suitable small web-server. Jetty is usually a good choice.

Upvotes: 0

Zach Scrivena
Zach Scrivena

Reputation: 29569

The TCP connection provides you with one InputStream and one OutputStream. You could just poll the InputStream continuously for the next command (and its inputs) on a dedicated thread. ByteBuffer.wrap(byte[] array) may be useful in interpreting the bytes as chars, ints, longs, etc. You could also pass objects around using serialization.

Upvotes: 0

David Allan Finch
David Allan Finch

Reputation: 1424

This should help. Lesson 1: Socket Communications

Upvotes: 0

Aaron Digulla
Aaron Digulla

Reputation: 328780

Have a small main method which sets up the socket and listens for incoming connections. Pass each connection to a worker object (possibly in its own thread).

The worker object should have two APIs: The server and the client. The client API gets a connection and reads data from it, the server API takes a connection and writes data to it.

I like to keep these two in a single class because that makes it much more simple to keep the two in sync. Use a helper class to encode/decode the data for transmission, so you have single point to decide how to transmit integers, commands, options, etc.

If you want to go further, define a command class and write code to serialize that to a socket connection and read it from it. This way, you worker objects just need to declare which command class they handle and the server/client API gets even more simple (at the expense of the command class).

Upvotes: 1

Alnitak
Alnitak

Reputation: 339985

I would

  1. put each command into a class of its own, where each class implements a specific interface (e.g. Command)

  2. create a Map<String,Command> which contains a lookup table from each command string to an instance of the class that implements that command

Upvotes: 0

Related Questions