Ruby Programming Language Enables Concise Network Programming

ometimes runtime performance requirements determine which programming language I use. For flat out runtime performance, I have always found that natively compiled Common Lisp or C++ really do the trick. For large-scale Web applications, I usually use Java because of its wealth of infrastructure software.

For other projects, I find myself using the Ruby programming language more and more. Not only is Ruby a high-performance programming language that minimizes software development and maintenance costs, but writing software in it is just fun! Ruby is a very concise programming notation, so you can write programs quickly. The readability of Ruby code also makes it easy to make changes later.

I currently use Ruby for small text-based utility programs and network programming, and I use Ruby on Rails for some Web application development. This article concentrates on using Ruby for network programming and provides examples for Web service implementations with Ruby. Don’t worry if you’re new to Ruby. You really don’t need to know much about it in order to get something from this tutorial. The Related Resources section in the left column offers links to other Ruby tutorials and books for further reading.

Simple Server-Side Ruby: a Web Server

The Ruby language is supported by a rich built-in library. This first example uses the TCPServer class to open a server socket on port 9090 and waits for incoming connections. The goal is to be able to handle HTML GET requests like

The following Ruby code opens a server TCP socket, accepts incoming session requests, and writes each incoming request back to the user’s browser:

Listing 1
require 'socket'server ='', 9090)while (session = server.accept) request = session.gets puts request session.print "HTTP/1.1 200/OK Content-type: text/html " session.print "Response from Ruby Web server " session.print "request was:" session.print request session.print "" session.closeend

The line “puts request” prints out incoming browser requests:

GET /foo?bar=123 HTTP/1.1GET /favicon.ico HTTP/1.1

The second line printed because my browser (Safari on OS X) requested a “favorite icon” for this Web site. Fetching this response also would be simple without using a Web browser but instead using some simple Ruby TCP client code (here I use the “open-uri” library, which allows a remote resource identified by a URI to be accessed like a local file):

Listing 2
require 'open-uri' # allows the use of a file like API for URLsopen("") { |file| lines = puts lines}

The output would be:

Response from a very simple Ruby Web serverrequest was:GET /foo?bar=123 HTTP/1.1

While extending this simple Web server to return local HTML files, etc. would be trivial, it wouldn’t make much sense: the standard Ruby library contains the flexible WEBrick Web server toolkit. If you want to set up a full-featured Web site using pure Ruby, use WEBrick! Using the standard library, you can create a full service Web server with just a few lines of code (from the WEBrick documentation):

Listing 3
require 'webrick'include WEBricks = => 9090, :DocumentRoot => Dir::pwd + "/htdocs")trap("INT"){ s.shutdown }s.start

Sometimes writing a simple Web server from scratch in Ruby is useful. Instead of returning HTML, a simple TCP socket server can return XML data. The next section illustrates this idea with the implementation of a REST-based Web service.

Implement a REST-Based Web Service

Representational State Transfer (REST) is a simple means for implementing Web services. While REST also supports HTTP authentication and PUT requests for sending data to a Web service, the examples in this section assume only the use of HTTP GET requests for Web services. The first simple example is a REST-based Web service that adds two numbers. The goal is to handle GET requests that look like this:

GET /add?x=123&y=9 HTTP/1.1

Since Ruby has great built-in support for regular expressions, you can start up the Ruby interactive interpreter IRB and experiment with a regular expression matcher until you get one that works:

Listing 4
irbirb(main):001:0> s="GET /add?x=123&y=9 HTTP/1.1"=> "GET /add?x=123&y=9 HTTP/1.1"irb(main):002:0> re=/x=(d+)&y=(d+)/=> /x=(d+)&y=(d+)/irb(main):003:0> x = re.match(s)=> #irb(main):004:0> x[1,4]=> ["123", "9"]irb(main):005:0> x[1]=> "123"irb(main):006:0> x[2]=> "9"irb(main):007:0>

Now you are ready for a server that is similar to the first example, but this example returns an XML payload instead of HTML:

Listing 5
require 'socket'server ='', 9090)re=/x=(d+)&y=(d+)/while (session = server.accept) request = session.gets numbers = re.match(request) answer = numbers[1].to_i + numbers[2].to_i session.print "HTTP/1.1 200/OK Content-type: text/xml " session.puts " " session.closeend

You could use the test client in Listing 2, but it is not a practical example. So you should change it slightly to accept a text string as an argument. You will need to URL encode the text string using code like this:

require 'CGI'CGI.escape("1 2 3://:$")

This produces: “1+2+3%3A%2F%2F%3A%24“.

The following example looks for a GET request like this:

GET /query=Why+did+the+dog+bite+the+cat%3F HTTP/1.1

Here, the query is URL encoded. The following example in Listing 6 simply finds the sub-strings “query=” and “http” and eats the text in between them as the input text:

Listing 6
require 'socket'require 'CGI'server ='', 9090)while (session = server.accept) request = session.gets puts request index = request.index("query=") + 6 index2 = request.index(" HTTP") query = request[index..index2] puts query answer = CGI.unescape("I don't know the answer to: " + query) session.print "HTTP/1.1 200/OK Content-type: text/xml " session.puts "" + answer + "" session.closeend

Implement an XML-RPC-Based Web Service

First, you need to write a simple XML-RPC client. You frequently will want to access other services that support an XML-RPC interface, so all you need to know is how to write clients. (However, you shortly will see how to also write XML-RPC services in Ruby.)

The Ruby built-in XML-RPC library automatically marshals values in Ruby variables to and from XML. This example uses string arguments, but arguments could also be numbers, arrays, etc. The following client accesses the services “upper_case” and “lower_case” from a server that supports XML-RPC and implements these services:

Listing 7
require 'xmlrpc/client'server ="", "/RPC2", 9090)puts"upper_case", "The fat dog chased the cat on Elm Street.")puts"lower_case", "The fat dog chased the cat on Elm Street.")

I have written XML-RPC services in Java, Common Lisp, Python, and Perl. I think that, using the WEBrick classes, Ruby’s XML-RPC library is the easiest to use. Here is server code that would process calls for the code in Listing 7:

Listing 8
require 'webrick'require 'xmlrpc/server.rb'# create a servlet to handle XML-RPC requests:servlet = XMLRPC::WEBrickServlet.newservlet.add_handler("upper_case") { |a_string| a_string.upcase }servlet.add_handler("lower_case") { |a_string| a_string.downcase }# create a WEBrick instance to host this => 9090)trap("INT"){ server.shutdown }server.mount("/RPC2", servlet)server.start

You can add any number of named handlers to a WEBrickServlet. These handlers can take zero or more arguments.

Implement a SOAP-Based Web Service

First, you write a simple SOAP client. You frequently will want to access other services that support a SOAP interface, so all you need to know is how to write clients. (However, you shortly will see how to also write SOAP services in Ruby.)

The Ruby built-in SOAP library automatically marshals values in Ruby variables to and from XML. The following client accesses the services “upper_case“, “lower_case“, and “times_string” from a server that supports SOAP and implements these services:

Listing 9
require 'soap/rpc/driver'stub ="", "")stub.add_method('upper_case', 'a_string')stub.add_method('lower_case', 'a_string')stub.add_method('times_string', 'a_string', 'a_number')puts stub.lower_case("Jack and Jill went up the hill.")puts stub.upper_case("Jack and Jill went up the hill.")puts stub.times_string("Jack and Jill went up the hill.", 2)

The code specifies that the SOAP server is at IP address (localhost) and listens for connections on port 9090. It specifies “” as a name space (must match what the server uses).

The server requires a class that implements the exposed methods “upper_case“, “lower_case“, and “times_string“; so you first implement DemoClass, which has these three methods:

Listing 10
require 'soap/rpc/standaloneserver'# define a class that has three methods to call remotely:class DemoClass def upper_case(a_string) a_string.upcase end def lower_case(a_string) a_string.downcase end def times_string(a_string, a_number) a_string * a_number endend# create a SOAP enabled server for the methods in DemoClass:class MyServer < SOAP::RPC::StandaloneServer def on_init demo = add_method(demo, "upper_case", "a_string") add_method(demo, "lower_case", "a_string") add_method(demo, "times_string", "a_string", "a_number") endendserver ="Demo", "", "", 9090)trap('INT') { server.shutdown }server.start

In Listing 10, after the code defines DemoClass for implementing the Web services, it sub-classes the SOAP standalone server class; the class on_init method adds methods to the class.

If you have ever written SOAP clients and services in other programming languages, you will appreciate how easy it is to use Ruby's SOAP libraries.

The Wrap-Up

For most applications, I like to use XML-RPC because it is lighter weight than SOAP and has implementations for more programming languages. REST is great for some applications that map well to a function-type call (think of the query URL as a function followed by arguments) returning an XML payload.

This article contained a lot of code, but hopefully you both understood the examples and ran the example code snippets without any problems. Want to go further with network programming in Ruby? Review the Related Resources section in the left column for more detailed information on the topics this article lightly covered.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin


The Latest

Why transparent code is a good idea

Why Transparent Code is a Good Idea

Code is used to make up the apps and software we use every day. From our favorite social media platforms to our online banking services, code is the framework used to build these tools that help make our lives easier. Code is complex. Software today requires large teams of programmers

The Role of WordPress Hosting in Website Speed and Performance

The Role of WordPress Hosting in Website Performance

The term “WordPress hosting” refers to a specific type of web hosting service that offers hardware and software configurations tailored to the needs of WP sites. It’s important to remember that a WP hosting package is not required to host WordPress webpages. WP web pages are also compatible with standard

Data Privacy vs. Data Security: What you Should Know

Data Privacy vs. Data Security: What you Should Know

Data privacy and data security are often used interchangeably, but they are two completely different things. It’s important to understand the difference for anyone who handles sensitive information, such as personal data or financial records. In this article, we’ll take a closer look at data privacy vs. data security. We’ll

Concerned About Company Data Security?

Company Data Security Concerns? Follow These 9 Tips

The days of doing all of one’s work at an office have long since passed. With technological progress, you can do most of the work from a remote location. It allows you to go on vacation anytime without affecting your work. It’s common to work from another location these days.

How to Access and Website With a Free VPN for PC

How to Access and Website With a Free VPN for PC

In the online world of today, you will come to realize that it is all-encompassing. The world has become hyper-digitalized and geared towards cyberspace. Whether it was always going to happen or driven by external factors. At the same time, events like the COVID-19 pandemic have shifted our activity toward