Network Programming with Perl


 
Network Programming with Perl

By Lincoln  D.  Stein

Slots : 1

Table of Contents
Chapter  18.   The UDP Protocol

    Content

Creating and Using UDP Sockets

As shown in the example of the last section, UDP datagrams are sent and received via sockets. However, unlike TCP sockets, there is no step in which you connect() the socket or accept() an incoming connection. Instead, you can start transmitting and receiving messages via the socket as soon as you create it.

UDP Socket Creation

To create a UDP socket, call socket() with an address family of AF_INET , a socket type of SOCK_DGRAM, and the UDP protocol number. The AF_INET and SOCK_DGRAM constants are defined and exported by default by the Socket module, but you should use getprotobyname (" udp ") to fetch the protocol number. Here is the idiom using the built-in socket() function:

socket(SOCK, AF_INET, SOCK_DGRAM, scalar getprotobyname('udp')) or die "socket() failed: $!";

The send() and recv() Functions

Once you have created a UDP socket, you can use it as an endpoint for communication immediately. The send() function is used to transmit datagrams, and recv() is used to receive them. We've seen send() and recv() before in the context of sending and receiving TCP urgent data (Chapter 17). To send a datagram, the idiom is this:

$bytes = send (SOCK,$message,$flags,$dest_addr);

Using socket SOCK , send() sends the message data that is contained in $message to the destination indicated by $dest_addr . The $flags argument, which in addition to controlling TCP out-of- band data can be used to adjust esoteric routing parameters, should be set to 0. The destination address must be a packed socket address created by sockaddr_in() . Like all other INET addresses, the address includes the port number and IP address of the destination.

send() will return the number of bytes successfully queued for delivery. If for some reason it couldn't queue the message, send() returns undef and sets $! to the relevant error message. Note that a positive response from send() does not mean that the message was successfully delivered, or even that it was placed on the network wire. All this means is that the operating system has successfully copied the message into the local send buffer. UDP is unreliable and guarantees nothing.

Having used a socket to send a message to one destination address, a program can turn right around and use send() to send a second message to a different destination. Unlike TCP, in the UDP protocol there is no long- term relationship between a socket and its peer.

To receive a UDP message, call recv() . This function also takes four arguments, and uses this idiom:

$sender = recv (SOCK,$data,$max_size,$flags);

In this case $data is a scalar that receives the contents of the message, $max_size is the maximum size of the datagram that you can accept, and $flags should once again be set to 0. The recv() call will block until a datagram is received. On receipt of a message, recv() returns the message contents in $data and the packed address of the sender in the function result. The sender address is provided so that you can reply to the sender.

If the received datagram is larger than $max_size , it will be truncated. If some error occurs, recv() returns undef and sets $! to the appropriate error code.

If you are familiar with the C-language socket API, you should know that the Perl recv() function is actually implemented on top of the C language recvfrom() call, not the recv() call itself.

Binding a UDP Socket

By default, the operating system assigns to a new UDP socket an unused ephemeral port number and a wildcard IP address of INADDR_ANY . Clients can usually accept this default, because when the client transmits a request to a server, its UDP datagram contains this return address, allowing the server to return a response.

However, a server application usually wants to bind its socket to a well-known port so that clients can rendezvous with it. To do this, call bind() in the same way you would with a TCP socket. For example, to bind a UDP socket to port 8000, you might use the following code fragment:

my $local_addr = sockaddr_in(8000,INADDR_ANY); bind (SOCK,$local_addr) or die "bind(): $!";

Once a UDP socket is bound, many systems do not allow it to be rebound to a different address.

Connecting a UDP Socket

Although it seems like an oxymoron, it is possible to call connect() with a UDP socket. No actual connection is attempted; instead the system stores the specified destination address of the connect() function and uses this as the destination for all subsequent calls to send() . You can retrieve this address using getpeername() .

After the UDP socket is connected, send() will accept only the first three arguments. You should not try to specify a destination address as the fourth argument, or you will get an "invalid argument" error. This is convenient for clients that wish to communicate only with a single UDP server. After connecting the socket, clients can send() to the same server multiple times without having to give the destination address repeatedly.

Should you wish to change the destination address, you may do so by calling connect() again with the new address. Although the C-language equivalent of this call allows you to dissolve the association by connecting to a NULL address, Perl does not provide easy access to this functionality.

A nice side effect of connecting a datagram socket is that such a socket can receive messages only from the designated peer. Messages sent to the socket from other hosts or from other ports on the peer host are ignored. This can add a modicum of security to a client program. However, connecting a datagram socket does not change its basic behavior: It remains message oriented and unreliable.

Servers that typically must receive and send messages to multiple clients should generally not connect their sockets.


   
Top

Категории