Socket Programming and Threads
Networking usually implies TCP/IP, the way in which millions of machines communicate back and forth across the Internet. Network communication is conceptualized at different layers - data link, network, transport and application. The application layer is the world of telnet, FTP, email protocols, and much more.
Let us talk a little bit about basic networking.
Our discussion of networking focuses on both sides of a client-server relationship. The client requests that some action be performed, and the server performs the action and responds to the client. A dedicated server spends its lifetime waiting for messages and answering them. A common implementation of the request-response model is between World Wide Web browsers and World Wide Web servers. When a user selects a Web site to browse through a browser (the client application), a request is sent to the appropriate Web server (the server application). The server normally responds to the client by sending an appropriate HTML Web page.
A port is not a physical device, but an abstraction to facilitate communication between a server and a client.
Ports are described by a 16-bit integer value. Hence, a machine can have a maximum of 65536 port numbers (ranging from 0 to 65535). The port numbers are divided into three ranges: the Well Known Ports, the Registered Ports, and the Dynamic and/or Private Ports. The Well Known Ports are those from 0 through 1023 (for example, port no. 80 is for http, port no. 25 is for smtp and so on). The Registered Ports are those from 1024 through 49151. The Dynamic and/or Private Ports are those from 49152 through 65535.
These are the numerical host addresses that consist of four bytes such as 188.8.131.52. The IP address 127.0.0.1 (localhost) is a special address, called the local loopback address, which denotes the local machine.
We shall develop sockets-based networking applications using the Ruby language. You need to have a basic familiarity with BSD-style sockets. Nowadays it is safe just to say "sockets". Previously one had to say "BSD sockets" because there were multiple socket APIs fighting for domination. Eventually, in the Unix/POSIX world the Berkeley Software Distribution (BSD) style socket API won out. Most *Nix programmers that do networking use BSD style sockets.
If you are accustomed to programming network connections in C or C++, you will be pleasantly surprised at how easy it is to program them in the Ruby programming language.
A socket represents a single connection between two network applications. These two applications nominally run on different computers, but sockets can also be used for inter-process communication on a single computer. Applications can create multiple sockets for communicating with each other. Sockets are bidirectional, meaning that either side of the connection is capable of both sending and receiving data.
Ruby has a rich and diverse set of sockets classes. These classes range from the standard Socket class (which mimics the BSD Sockets API) to more refined classes that focus on a particular protocol or application type.
The class hierarchy of the base sockets classes is as shown below:
The above figure is from the book Programming Ruby.
Most of the classes derive from the IO class. This means that we can use the methods of IO that are so familiar to us. The TCPSocket class supports sockets for the connection-based, reliable Transmission Control Protocol. A helper class for the creation of TCP server sockets is also available in the TCPServer class. To create a stream socket and connect it to a server, the TCPSocket class can be used. All socket classes are part of the standard library (and not part of the core classes), so to use them in your Ruby program, you must first write: require 'socket'
You should refer to this quick guide on Ruby Threads before you proceed to the program that follows.
The Date Time Server and Client
Now let us build a Ruby-based Date Time server and client that displays on the client computer the date and time at the dedicated server hosting location, using the Ruby socket API. Here's the code for the Date Time Server - p068dtserver.rb
Explanation of the p068dtserver.rb code:
You first load the socket library with the require command. The TCPServer class is a helper class for building TCP socket servers. The TCPServer.new('localhost', 20000) statement creates a new socket identified by localhost and port number. The Thread.start creates and runs a new thread to execute instructions given in block. Any arguments passed to Thread.start are passed into the block. The dts.accept method waits for a connection on dts, and returns a new TCPSocket object connected to the caller. The Kernel.loop iterator calls the associated block do..end) forever (or at least until you break out of the loop). We use s.write(Time.now) to write the current date and time on the server to the socket. Finally, we write s.close to close a socket using the close method. This method is inherited from the IO class, but it's available for each of the socket types.
Running the server
Since we are testing these programs on our local machine, open a new command window, go to the folder containing your p068dtserver.rb program and type ruby p068dtserver.rb. The program runs and waits for a client to connect at port 20000.
Here's the code for the Date Time Client - p069dtclient.rb
Explanation of p069dtclient.rb code:
You first load the socket library with the require command. The statement sock = TCPSocket.new('127.0.0.1', 20000) opens a TCP connection to localhost on port 20000. The statement str = sock.recv(100) receives up to 100 bytes from sock. We display the date-time string received from the server and finally we close the socket.
This topic has explored the classes that make networking application development possible in Ruby. It discussed the basic classes for sockets programming (such as the Socket class) and also the classes that help to simplify sockets programming in Ruby, such as TCPSocket and TCPServer.
Note: The Ruby Logo is Copyright (c) 2006, Yukihiro Matsumoto. I have made extensive references to information, related to Ruby, available in the public domain (wikis and the blogs, articles of various Ruby Gurus), my acknowledgment and thanks to all of them. Much of the material on rubylearning.com and in the course at rubylearning.org is drawn primarily from the Programming Ruby book, available from The Pragmatic Bookshelf.