Dienstag, 2. August 2022

Linux named pipes - a nice discovery in the hand of netcat

 Most of the software developer have implemented an application with an REST interface. The nice thing working with REST is, that for testing or whatever purpose, an curl request can be made. But what if the application speaks with a protocol which contains binary data or a binary header. What makes it worse is, if the protocol has its own hand shake and therefor it is needed to send different network frames  depending on requests or responses of the communication partner. It would be nice if that could be all done with a tool like netcat (nc). It is possible using netcat reading from a fifo or named pipe.    

Creating a named pipe is easy:

:~$ mktemp -d
/tmp/tmp.6FxU69SgTJ

:~$ mkfifo /tmp/tmp.6FxU69SgTJ/fifo

:~$ ls -l /tmp/tmp.6FxU69SgTJ
prw-r--r-- 1 user group 0 Aug  2 12:14 fifo

Now there is a fifo under a temporary directory and the first steps are done with cat. cat is used with the input from the fifo.
:~$ cat < /tmp/tmp.6FxU69SgTJ/fifo
cat is now waiting on input from the fifo. Currently it is blocked on the fifo because the reader on a fifo is blocked for a writer. If something is written o a different shell with the help of echo, it can be seen that the cat command print the result but also finished, which is not the expecting result.
:~$ echo something > /tmp/tmp.6FxU69SgTJ/fifo/
:~$ cat < /tmp/tmp.6FxU69SgTJ/fifo/
something
:~$

After looking a little bit around in the internet and especially on stackoverflow, the shell builtin command exec comes into the game. It is possible to open a new stream and redirect all to the fifo. First start the cat command again:
:~$ cat < /tmp/tmp.6FxU69SgTJ/fifo/
Redirect all output via filedescriptor 3 to the fifo.
:~$ exec 3> /tmp/tmp.6FxU69SgTJ/fifo/
Now it is possible to write some words with echo and the cat command is showing them all without to stop.
:~$ echo some > /tmp/tmp.6FxU69SgTJ/fifo/
:~$ echo command > /tmp/tmp.6FxU69SgTJ/fifo/

# The cat command in the other shell
:~$ cat < /tmp/tmp.6FxU69SgTJ/fifo/
some
command

As the output from 3 redirected to the fifo it is a bit more easier to redirect stdout to 3 and not to the fifo directly because 3 is always directed to the fifo.
:~$ echo some >&3 
:~$ echo command >&3

# The cat command in the other shell
:~$ cat < /tmp/tmp.6FxU69SgTJ/fifo/
some
command

Now it is time to try the whole thing with netcat:
# start a new shell with a netcat listener which gets the commands from echo
:~$ netcat -l -p 2628 < /tmp/tmp.6FxU69SgTJ/fifo/

# start a new shell with a netcat client
:~$ netcat localhost 2628

# now we get the netcat listener to do what we say (here with some binary data which does not make sense here but in different cases)
echo -n -e '\x02\x00\x00\x09\x03Some' >&3
echo -n -e '\x02\x00\x00\x0C\x03Command' >&3 

# the netcat client received all the frames we send via echo to the fifo. 
# We can't really display the binary data here.

Do not forget the close the filedescriptor after usage, otherwise it stays open and can't be used in other cases.
:~$ exec 3>&-

Without the internet especially stackoverflow, I would never get to that solution. With the help of this functionality it is much more easier to play with some network protocols. Thanks to all the people who share their knowledge.

Mittwoch, 12. März 2014

Netty TCP client with reconnect handling

There are situations where it makes sense to have a netty client doing a reconnect in case of a lost connection. There are 2 states where we need to do a reconnect:

  • The client gets no connection at startup
  • The client lost the connection during processing
Getting both situations handled we need to implement a ChannelFutureListener which handles the reconnect during the bootstrap phase and of course a ChannelHandler which we can use to get informed if the channel gets inactive.
We starting with a small bootstraping client:

 public class Client  
 {  
   private EventLoopGroup loop = new NioEventLoopGroup();  
   public static void main( String[] args )  
   {  
     new Client().run();  
   }  
   public Bootstrap createBootstrap(Bootstrap bootstrap, EventLoopGroup eventLoop) {  
     if (bootstrap != null) {  
       final MyInboundHandler handler = new MyInboundHandler(this);  
       bootstrap.group(eventLoop);  
       bootstrap.channel(NioSocketChannel.class);  
       bootstrap.option(ChannelOption.SO_KEEPALIVE, true);  
       bootstrap.handler(new ChannelInitializer<SocketChannel>() {  
         @Override  
         protected void initChannel(SocketChannel socketChannel) throws Exception {  
           socketChannel.pipeline().addLast(handler);  
         }  
       });  
       bootstrap.remoteAddress("localhost", 8888);
       bootstrap.connect().addListener(new ConnectionListener(this)); 
     }  
     return bootstrap;  
   }  
   public void run() {  
     createBootstrap(new Bootstrap(), loop);
   }  
 } 
The createBootstrap method is public because we need it to be called from within the reconnect handler.

The following shows the ConnectionListener which is responsible for reconnecting during connect invocation. If the connect fails we schedule a reconnect within the eventloop of the channel which means basically create the bootstrap again and try another connect.

 public class ConnectionListener implements ChannelFutureListener {  
   private Client client;  
   public ConnectionListener(Client client) {  
     this.client = client;  
   }  
   @Override  
   public void operationComplete(ChannelFuture channelFuture) throws Exception {  
     if (!channelFuture.isSuccess()) {  
       System.out.println("Reconnect");  
       final EventLoop loop = channelFuture.channel().eventLoop();  
       loop.schedule(new Runnable() {  
         @Override  
         public void run() {  
           client.createBootstrap(new Bootstrap(), loop);  
         }  
       }, 1L, TimeUnit.SECONDS);  
     }  
   }  
 }  

The same as we do in the connection listener is done in the ChannelHandler below. If we lost the connection to the server we schedule a reconnect from within the handler which is also basically just create a new bootstrap and try to connect again.

 public class MyInboundHandler extends SimpleChannelInboundHandler {  
   private Client client;  
   public MyInboundHandler(Client client) {  
     this.client = client;  
   }  
   @Override  
   public void channelInactive(ChannelHandlerContext ctx) throws Exception {  
     final EventLoop eventLoop = ctx.channel().eventLoop();  
     eventLoop.schedule(new Runnable() {  
       @Override  
       public void run() {  
         client.createBootstrap(new Bootstrap(), eventLoop);  
       }  
     }, 1L, TimeUnit.SECONDS);  
     super.channelInactive(ctx);  
   }  
 }  

This is all to get a netty client with reconnection handling at least for me. I don't know if it is the right way to do it but it works at least for me. You are welcome to post better solutions or maybe the right solution or just some corrections. 

Freitag, 11. März 2011

Guter Shop für Elektromaterial!

Hier mal ein guter Anbieter für Elektromaterial!

Mittwoch, 7. April 2010

my new toy

Today I got my system board MK2 from myAVR. Ordered yesterday, received today - really fast shipping. I'm really excited to start some testing with it.


Von diverses


Cheers

For a friend of mine

http://sanostools.de

Just a link to his new shop.

Cheers