Sockets Enable Multi-Lingual Applications

As we work with our clients to delivery new features to them quickly and with high quality code, we are finding that the fastest way forward is often writing code in Ruby. The problem is that in many cases we are working with an existing application written in a different language.

We may need to add a feature to a C++ application or integrate with a Java Library. One of our favorite solutions in this situations is to have multiple applications talking to each other over sockets.

We’ve found that using sockets to communicate between applications is a great way to ‘bolt on’ new functionality. This type of communication has been around for a long time and nearly every language has socket communication in standard libraries or in free open source projects.

Dean Wampler suggested that Applications Should Use Several Languages and socket communication is another way to enable this.

Socket Basics

Most internet communication is built on socket communication, so I won’t try to go into great detail here. I don’t pretend to be an expert. Here is what you need to understand about sockets to use them in your applications.

UDP vs. TCP

There are two basic types of IP socket protocols: UDP and TCP. UPD is what I’ll call a ‘send and pray’ protocol.

In UDP there is really no difference between server and client. Each node can listen on some port and write on some port. Messages are sent from point to point or broadcast to all nodes. Either way, delivery is not guaranteed. The message will likely make it to the destination, but there are a host of things that could happen that would prevent delivery. Worse, as the sender you can’t know whether of not your message made it unless you implement some kind of response protocol on top.

I’ve used UDP communications for monitoring/metering applications where it isn’t important that every message be delivered, but I’ve also found that I usually end up implementing some kind of delivery guarantee mechanism anyway.

TCP sockets build another layer on top of basic IP communication that guarantees delivery. Once a connection is established between client and server, both sides can communicate knowing their message will be received.

On the Server side, a socket listens on a particular port for new connections. Most libraries call this operation ‘accept.’ A client ‘opens’ a connection to the server. This process involves the client and the server agreeing on a new port for communication. If the server is going to accept multiple connections, then it usually launches a new thread to handle each new connection.

I use TCP Sockets for most inter-application communication. It turns out that in most situations, I want that guaranteed delivery and don’t want to bother with my own acknowledgment protocol. So it’s the TCP Socket that I’ll show you for now.

Over my next few posts, I’ll show you how to communicate via sockets in many languages. We’ll start with Ruby. Ruby has TCPSockets built in, though there really isn’t much documentation on how to use it. Here is how to do it.

The TCPSocket class can be found in ‘socket:’

1 require 'socket'

Create a socket server. The first parameter is the address to listen on. If you specify 0.0.0.0 then the server will accept connections from any host. If you specify localhost or 127.0.0.1 this the server will only accept connections from sockets on the same computers. The port can be anything you want. Be sure to avoid commonly used ports.

1 server = TCPServer.new('localhost', '4138')

Now, when you call accept on the server it will block until a client opens up a connection.

1 server_socket = server.accept

Now that the server is waiting for a new connection, let’s open that connection from a client. Note that this needs to be happening in a separate ruby process. The first parameter is the host address or name of the server. The second is the port on which the server is listening.

1 require 'socket'
2 client_socket = TCPSocket.new('localhost', '4138')

Now that there is as new connection open the client and server can talk back and forth at will. In this example, the server just echoes the clients message back to it. So all together, the Server side looks like this:

1 require 'socket' 
2 server = TCPServer.new('localhost', '4138') 
3 server_socket = server.accept
4 message = server_socket.recvfrom(256)[0]
5 server_socket.write("You Said: #{message}")

And the Client side:

1 require 'socket'
2 client_socket = TCPSocket.new('localhost', '4138')
3 print "Enter Message:  "
4 input = gets
5 client_socket.write(input)
6 response = client_socket.recvfrom(256)[0]
7 puts response

So that’s it, you are communicating between two applications with sockets. If we want the server to continue processing messages, we can loop reading from the socket:

1 require 'socket' 
2 server = TCPServer.new('localhost', '4138') 
3 server_socket = server.accept
4 
5 message = ""
6 until message.chomp == "quit" do
7     message = server_socket.recvfrom(256)[0]
8     server_socket.write("You Said: #{message}")
9 end

So far our server can only handle one connection at a time. Often times, you’ll want multiple client to be able to open up connections to the server. To do this, we’ll need to launch a new thread each time a client connects.

This is a little class that does that. You can implement your own handler object to handle each socket. The handler only needs a ‘serve’ method that takes a socket. The ThreadGroup is a nice little class to keep track of the threads. When a thread finishes, it is automatically removed from the thread group.

 1 require 'socket' 
 2 
 3 class MultiTcpServer
 4 
 5   def initialize(handler, port)
 6     @group = ThreadGroup.new
 7     @handler = handler
 8     @server = TCPServer.new('0.0.0.0', port) 
 9   end
10 
11   def connections_open
12     return @group.list.size
13   end
14 
15   def run
16     begin
17       loop do
18         socket = @server.accept
19         @group.add(Thread.new {@handler.serve(socket)})
20       end
21     rescue IOError
22     end
23   end
24 
25   def stop
26     @server.close
27   end
28 
29 end

Hopefully this little tutorial was helpful. Next time I’ll take a look at sockets in C++ or Java.

Doug Bradbury, Director of Software Services

Doug Bradbury is a maker, a thinker, a craftsman, and a learner.