In the previous section we looked at creating a basic TCP client using net/telnet. However, to demonstrate a basic client/server system, UDP is an ideal place to start. Unlike with TCP, UDP has no concept of connections, so it works on a simple system where messages are passed from place to another with no guarantee of them arriving. Whereas TCP is like making a phone call, UDP is like sending a postcard in the mail.
Creating a UDP server is easy. Let’s create a script named udpserver.rb:

require 'socket'
s = UDPSocket.new
s.bind(nil, 1234)
5.times do
  text, sender = s.recvfrom(16)
  puts text
end

This code uses Ruby’s socket library, a library that provides the lowest-level access to your operating system’s networking capabilities. socket is well suited for UDP, and in this example you create a new UDP socket and bind it to port 1234 on the local machine. You loop five times, accepting data in 16-byte chunks from the socket and printing it to the screen.

■ Note The reason for looping just five times is so that the script can end gracefully after it receives five
short messages. Later, however, we’ll look at ways to keep servers running permanently.

Now that you have a server, you need a client to send data to it. Let’s create udpclient.rb:

require 'socket'
s = UDPSocket.new
s.send("hello", 0, 'localhost', 1234)

This code creates a UDP socket, but instead of listening for data, it sends the string “hello” to the UDP server on localhost at port 1234. If you run udpserver.rb at the same time as udpclient.rb, “hello” should appear on the screen where udpserver.rb is running. You have successfully sent data across a network (albeit on the same machine) from a client to a server using UDP.
It’s possible, of course, to run the client and server on different machines, and if you have multiple machines at your disposal, all you need to do is change ‘localhost’ on the send method to the hostname or IP address of the machine where udpserver.rb is running.
As you’ve seen, UDP is simple, but it’s possible to layer more-advanced features on top of it. For example, because there is no connection involved, you can alternate between client and server modes with a single program, accomplishing a two-way effect.
You can demonstrate this easily by making a single program send and receive UDP data to and from itself:

require 'socket'
host = 'localhost'
port = 1234
s = UDPSocket.new
s.bind(nil, port)
s.send("1", 0, host, port)
5.times do
  text, sender = s.recvfrom(16)
  remote_host = sender[3]
  puts "#{remote_host} sent #{text}"
  response = (text.to_i * 2).to_s
  puts "We will respond with #{response}"
  s.send(response, 0, host, port)
end

■ Note In a real-world situation you would typically have two scripts, each on a different machine and
communicating between each other, but this example demonstrates the logic necessary to achieve that
result on a single machine for ease of testing.

UDP has some benefits in speed and the amount of resources needed, but because it lacks a state of connection and reliability in data transfer, TCP is more commonly used. Next we’ll look at how to create some simple TCP servers to which you can connect with net/telnet and other applications.

Advertisements