UDP Echo Client :
udpcliserv/ udpcli01.c Page No: 216
#include "unp.h"
int
main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: udpcli
<IPaddress>"); bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET; servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr); sockfd = Socket(AF_INET,
SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) &servaddr,
sizeof(servaddr)); exit(0);
}
An IPv4 socket address structure is filled in
with the IP address and port numbers of the server. This structure is passed on
to dg_cli.
A UDP socket is is created and the function
calls dg_cli.
Dg_cli Function
#include "unp.h"
void dg_cli(FILE *fp, int sockfd, const SA
*pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE],
recvline[MAXLINE + 1];
while (Fgets(sendline, MAXLINE, fp) != NULL) {
sendto (sockfd, sendline, strlen(sendline, 0,
pservaddr, servlen);
n = recvfrom(sockfd, recvline,
MAXLINE,0,NULL,NULL);
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
With a
UDP socket, when the first time the call to sendto() is given, the port is
bound to it. Also similar to server, client can also call for bind() to tie up
its port.
In the
recvfrom(), a null pointer is specified in the fifth and sixth argument. Which
means that we are not interest in knowing who has send the datagram. This may
result in error in reception of datagram, as the same host or any other host
may send datagram which is likely to be mistaken.
Similar
to dg_echo(), dg_cli() is also protocol independent. In this the main function
allocates and initializes a socket address structure of some protocol type and
then passes pointer to this structure along with its size.
Lost Datagrams:
Above
client server example is not reliable. If the client datagram is lost, (may be
dropped at any router), the client will block its recvfrom() forever waiting
for a server reply that will never arrive. Similarly if the client datagram
arrives at the server but the server‘s reply is lost, the client will once
again block the recvfrom(). A time out and a appended number is normally sent with
the datagram which is sent back as acknowledgment with reply. This will assure
whether the datagram is received or not. This facility is provided many UDP
servers.
Verifying the Received Response : It is seen from the above example that any
process that knows the clients
ephemeral port number could datagram to our client and these will be
interpreted with the normal server replies. It can be avoided by comparing the
IP address and port number of the recvfrom() (reply received from server), with
that of the IP address and port number to which it was sent earlier. This
requires creating a socket address structure in which the return address
structure is returned and
compared with
the sent address structure.
This is shown in the following example
udpcliserv/dgcliaddr.c Page No : 219
dg_cli(FILE *fp, int sockfd, const SA
*pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE],
recvline[MAXLINE + 1];
socklen_t len;
struct
sockaddr *preply_addr;
prpeply_addr = malloc(servlen);
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr, servlen); Len =
servlen;
n = Recvfrom(sockfd, recvline, MAXLINE, 0,
preply_addr, &len); if (len != servlen|| memcmp (pservaddr, preply_addr,
len)!= 0) {printf (reply from %s (ignored)\n―),sock_ntop (preply_addr, len);
continue;
}
Recvline[n]
= 0; /* null terminate */
Fputs(recvline, stdout);
}
}
First
the, client main function is changed to use the standard echo server. Servaddr.sin_port = htons(SERV_PORT) changed to servaddr.sin_port = htons (7). Malloc()
function allocates the byte size to
the structure. With this arrangement, the received address captured in
preply_addr is compared with the one that was sent in sendto(). First a
comparison is made of its length and then memcopy compares then socket address
itself is compared. This will assure if the server address is same.
However,
even this may not work if the server is multi homed where in it is likely to
allocate different IP address as the server has not bound an IP address to its
socket and it chooses any IP Address. Hence this may also fail.
One
solution is for
the client to verify the responding host‘s domain
name instead of its IP
address by looking up the server‘s name in the
DNS, given the IP address returned by recvfrom().
Another
solution is for the server to create one socket for every IP address that is
configured on the host , bind that IP address to the socket, use select across
all these sockets (waiting for one to be readable) and then reply from the
socket that is readable. Since the socket used for the reply was bound to the
IP address that was the destination address of the client request, this
guarantees that the source address for the reply is the same as the destination
address of the request.
Server not Running :
If the client sends a datagram to a server that
is not yet started, what happens to it? The recvfrom() will be blocked for ever
waiting for a reply from the server. When the call to sendto() is given by
passing the massage to it, the function returns OK ( size of message to
application) which means that datagram is put in the output interface queue for
further transmission. Where as the datagram traveling to server that is not
switched on, is responded with an ICMP port unreachable error. As this error
takes more time to return (equal to RTT), this error is known as asynchronous
error - not synchronous with the error causing source, which in this case is
sendto().
This error is not returned to UDP socket at the
client. Hence, the recvfrom() is left open. The asynchronous error can be
returned only when the socket have been connected which requires a call to
connect() by the client.
connect() with UDP:
As it was seen that asynchronous errors are not
returned to UDP sockets unless the socket has been connected. It is possible to
give a call to connect() in UDP also. But it does involved few changes that are
listed below:
1. When connect() is called, the destination IP
address and port number of the server host is provided. Hence there is no
requirement to pass these values in sendto(). Hence, the functions sendto() is
replaced with write() or send() functions. This assumes that anything written
is automatically send to the server address specified in the connect function.
2. Similarly, recvfrom() is also not used
instead recv() or read() functions are used. The only datagram returned by the
kernel for an input operation on a connected UDP socket are those arriving from
protocol address specified in the connect. Datagram destined to the connected
UDP sockets local protocol address but arriving from a protocol address other
than the one to which the socket was connected, are not passed to the connected
socket. This limits the connected UDP socket to exchanging datagram with one
and only peer.
3 Asynchronous errors are returned to the
process for a connected UDP socket. Also an unconnected UDP sockets does not
receive any asynchronous error.
It can be said that UDP client or server can
call connect() only if that process uses UDP socket to communicate with exactly
one peer.
Calling connect () Multiple Times for a UDP socket:
A process with a connected UDP socket can call
connect() function again for that socket to either
•
Specify
a new IP address and p ort or to,
•
Unconnect
the socket.
Unlike in the case of TCP, where in the
connect() is called only once, in the case of UDP, it can be called again.
To
unconnect, the connect is called by setting the family members of the socket
address structure (sin_family for IPv4 and sin6_family for IPv6) to AF_UNSPEC.
This might return EAFNOSUPPORT error but it is accepted.
Performance:
When an
application calls sendto() on an unconnected UDP socket, Berkeley derived
kernels temporarily connect the socket, and datagram and then un connect the
socket . Calling sendto for two datagram on unconnected UDP socket then
involves the following six steps:
•
Connect the socket.
•
Output
the first datagram.
•
Unconnect
the socket.
•
Connect
the socket.
•
Output
the second datagram
•
Unconnect
the socket.
When the application knows that it will be
sending multiple datagram to the same peer, it is more efficient to connect the
socket explicitly by calling connect() function and then call write() function
as many times. As shown below:
•
Connect
the socket/
•
Output
the first datagram and
•
Output
the second datagram.
IN this case the kernel copies only the socket
address structure containing the destination IP address and port one time,
versus two times when sendto is called twice.
The dg_cli function with call to connect function
is given below:
#include "unp.h"
void
dg_cli(FILE *fp, int sockfd, const SA
*pservaddr, socklen_t servlen)
{ int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
Connect(sockfd, (SA *) pservaddr, servlen);
while
(Fgets(sendline, MAXLINE, fp) != NULL) { Write(sockfd, sendline,
strlen(sendline));
n = Read(sockfd, recvline, MAXLINE);
recvline[n] = 0; /* null terminate */ Fputs(recvline, stdout);
} }
The changes are the new call to connect and
replacing the calls to sendto() and recvfrom() with calls to write() and
read(). This functions are still protocol independent.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.