As we saw last class, there are two big differences in code
between UDP and TCP.
- The second argument to the
socket system
call is SOCK_DGRAM instead of
SOCK_STREAM, and
- data is not sent/recieved with the familiar read/write
system calls (or fscanf/fprintf C IO calls).
Obviously, point 1 is trivial. What about point 2?
Fundamentally, read/write/fscanf/fprintf all assume a file
descriptor that provides a stream-of-characters ... precisely
what we don't have for UDP. With UDP each datagram needs to
be sent with a destination address, so whatever function
allows us to send data is going to need extra parameters for
passing the host+port. When we recieve a datagram, we really
don't know in advance where it's coming from, so whatever
function we use for recieving will need extra parameters to
provide us with the host+port from whence the datagram came.
The two system calls we'll discuss for sending/recieving
datagrams are:
ssize_t sendto(int s, const void *msg, size_t len, int flags, const struct sockaddr *to, int tolen);
ssize_t recvfrom(int s, void *buf, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen);
/***********************************************************
* A simple UDP server program. It just reads messages and
* prints them out along with the identity of sending host.
***********************************************************/
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
int main(int argc, char **argv)
{
/* Set up socket */
int sfd = socket(AF_INET,SOCK_DGRAM,0);
if (sfd == -1) { fprintf(stderr,"Socket not created!\n"); exit(1); }
/* Get current host's IP address. */
struct hostent *p;
p = gethostbyname(getenv("HOST"));
if (p == NULL) { fprintf(stderr,"Name not found!\n"); exit(2); }
unsigned int *ip = (unsigned int*)(p->h_addr_list[0]);
/* Set up address structure */
struct sockaddr_in mysa;
mysa.sin_family = AF_INET;
mysa.sin_addr.s_addr = *ip;
mysa.sin_port = htons(10000);
/* Bind socket to address */
if (bind(sfd,(struct sockaddr*)&mysa,sizeof(mysa)) < 0)
{
close(sfd);
fprintf(stderr,"bind failed!\n");
exit(3);
}
while(1)
{
/* Define buffer in which to recieve client's message. */
char msg[257] = {'\0'};
/* Set up structure for client's host+port and recieve datagram! */
struct sockaddr_in sourcesa = {0};
int ssize = sizeof(sourcesa);
int r = recvfrom(sfd,msg,256,0,(struct sockaddr*)&sourcesa,&ssize);
/* Print host and message. */
struct hostent *he= gethostbyaddr((char *)&sourcesa.sin_addr.s_addr,4,AF_INET);
printf("Got message from '%s' (IP %u)!\n",he->h_name,sourcesa.sin_addr.s_addr);
if (r == 0)
printf("-->%i-byte message!\n",r);
else
printf("-->%i-byte message: %s",r,msg);
}
fprintf(stderr,"Server shutting down!\n");
close(sfd);
return 0;
}