Monday, July 23, 2007

Using Grizzly to read TCP Packets

Recently I had the need to be able to listen on a port and read TCP packets that were sent from a logger (java.util.SocketHandler), and I wanted to utilize the Grizzly framework to do this. With some help from the Grizzly team I was able to accomplish this and thought I would share what I did. The first thing I had to do was write a main that could connect to a port and receive TCP packets, it looked something like the following:

public class TCPProcessor {
public static void main(String[] args) throws Exception {
int port = Integer.getInteger(args[0]);

Controller controller = new Controller();
TCPSelectorHandler tcpHandler = new TCPSelectorHandler();
final MyProtocolFilter filter = new MyProtocolFilter();

tcpHandler.setPort(port);
controller.setProtocolChainInstanceHandler(new DefaultProtocolChainInstanceHandler() {
public ProtocolChain poll() {
ProtocolChain protocolChain = protocolChains.poll();

if (protocolChain == null) {
protocolChain = new DefaultProtocolChain();
protocolChain.addFilter(new ReadFilter());
protocolChain.addFilter(filter);
}

return protocolChain;
}
});
controller.addSelectorHandler(tcpHandler);
controller.start();
}
}
Now that I have my main listening, I need to write the Filter that will handle the processing of the data packet. With the ProtocolChain, the ReadFilter will read the TCP packets and pass it to the next filter in the chain, which is were I need to process my data. My filter will look something like the following:
public class MyProtocolFilter implements ProtocolFilter {
public boolean execute(Context context) {
final WorkerThread workerThread = ((WorkerThread)Thread.currentThread());
String message = "";
ByteBuffer buffer = workerThread.getByteBuffer();
buffer.flip();

if(buffer.hasRemaining()) {
byte[] data = new byte[buffer.remaining()];
int position = buffer.position();
buffer.get(data);
buffer.position(position);
message = new String(data);
}
System.out.println("New message being read, message is: " + message);
buffer.clear();
return false;
}

public boolean postExecute(Context context) throws IOException {
return true;
}
}

So now you could whip up a test to send some data over TCP and the Processor will read the packets and print the message out.

5 comments:

imunk said...

how to send message via TCP to test this example?I am newbie

Chad Gallemore said...

One of the easiest ways you could do this is to install Groovy, spin up the Groovy Console and execute the following script:

s = new Socket("localhost", 8283)
s << "Groovy Rocks"
s.close()

So, get a new Socket, send the data, and close your Socket. Hope that helps you out. Otherwise you could do something similar with Java, it would just take a little more code.

Chad Gallemore said...

Oh yeah, make sure when you create your socket, you use the right Port. For example in the Reading TCP Packets example you set the port by passing it in with the args when you kick off the main. So for the example I gave you were going to send in data over port 8283, you would want to pass in 8283 as your argument when you kick off the main for the Socket Listener.

Eduardo DOT a20 AT gmail said...

I've been trying for 1 hour to put grizzly Echo filter to work properly (echo should happen after a CR LF only). Grizzly design is not elegant at all.

Anonymous said...

Sorry for my bad english. Thank you so much for your good post. Your post helped me in my college assignment, If you can provide me more details please email me.