| < Day Day Up > |
|
Now, let’s look at a UDP server and client implementation using datagram sockets. Recall that datagram communication is not connection-oriented; therefore, each datagram that we send must also include the intended recipient.
The datagram server is illustrated in Listing 20.4. After making the socket classes visible using the required method, we create our UDP socket using the UDPSocket::new method (line 4). We specify only that the UDP socket be of the AF_INET family. This is actually an optional argument, because the default is automatically Socket::AF_INET. The return of UDPSocket::new is the server socket.
In order to be visible to external clients, we name our UDP socket using the bind method (line 7). We bind to the “localhost” interface and the datagram port (13). Once bound, we emit the server address information using the addr::join method pair (as discussed previously with the stream server).
At line 13, we begin our server’s infinite loop to accept client datagrams and emit to them the current time in string form. At line 16, we await a datagram from the client using the recvfrom method. This method is used because we need to know the source of the datagram in order to know where to send the time string. We specify that we’re expecting a datagram of size 0 (no payload data) and we specify no flags. When a datagram does arrive, the recvfrom method returns two values. The first is the actual datagram payload (there won’t be one in this example) and the second is the source of the datagram.
At line 19, we respond to the client using the send method. The send method used here is a variant of the traditional send using a number of optional parameters to specify the destination of our datagram. The first parameter in send is the string we’re going to send (our datagram payload). This is made up of a time string returned by the Time::new::asctime method appended with a newline. The second parameter is the flags settings (0). The third and fourth parameters are the host and port to which the datagram will be sent. We use the previously received from parameter that contains the host in the third element (from[2]) and the port in the second element (from[1]).
Finally, we continue the infinite loop from line 22 and await another client datagram at line 16.
Listing 20.4 Ruby Daytime datagram server.
1 require ‘socket’ 2 3 # Create a new UDP Socket 4 servsock = UDPSocket::new(Socket::AF_INET) 5 6 # Bind the server socket to the daytime port 7 servsock.bind("localhost", "daytime") 8 9 # Debug data -- emit the server socket info 10 print("server address : ", servsock::addr::join(":"), "\n") 11 12 # The big loop 13 while true 14 15 # Receive a datagram from a client 16 reply, from = servsock.recvfrom(0, 0) 17 18 # Emit the time through the socket to the client 19 servsock.send( Time::new::asctime+"\n", 0, 20 from[2], from[1] ) 21 22 end
The datagram client is shown in Listing 20.5, and corresponds with the datagram server previously shown in Listing 20.4.
Listing 20.5 Ruby Daytime datagram client.
1 require ‘socket’ 2 3 # Create a new UDP Socket 4 clisock = UDPSocket::new(Socket::AF_INET) 5 6 # Send a zero-length datagram to the server on the daytime port 7 clisock.send("", 0, "localhost", "daytime") 8 9 # Await receipt of the time from the server 10 print clisock.recv(100) 11 12 # Close the socket 13 clisock.close
For the client, we create our datagram socket at line 4 using the UDPSocket::new method. Though the default, we specify the address family for the socket as Socket::AF_INET. At line 7, we send our empty datagram using the send method to let the server know that we’d like to receive a time string. This datagram serves only to notify the server of our address for the return datagram containing the time. We specify four parameters to the send method, an empty string representing the zero-length payload, optional flags, destination for the datagram (in this case, the “localhost" interface), and the port (“daytime”, or 13).
We then await the response datagram containing the time string at line 10. We use the recv call here instead of recvfrom because we’re not interested in the source address information. We print the string out immediately upon return rather than storing it first in a temporary string. Finally, at line 13, we close the socket using the close method.
| < Day Day Up > |
|