|
UDP Socket Programming
An Introduction with Examples in C |
|
Prof. David Bernstein |
| Computer Science Department |
| bernstdh@jmu.edu |
sockaddr:
struct sockaddr_in address; memset(&address, 0, sizeof(address)); address.sin_family = AF_INET; address.sin_port = htons(WELL_KNOWN_PORT); // For this service address.sin_addr.s_addr = htonl(INADDR_ANY);
ssize_t recvfrom(int fd, void *buffer, size_t buflen, int flags, struct sockaddr *src_addr, socklen_t *addrlen)
fd
|
The file descriptor of the UDP socket |
buffer
|
The buffer to fill with the datagram's payload |
length
|
The length of the buffer |
flags
|
Flags (often 0) |
src_addr
|
The address the datagram was sent from |
addrlen
|
The length of the source's address |
| Return | The number of bytes received on success; -1 on error |
#include <arpa/inet.h> // For byte order conversions
#include <string.h> // For memset()
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
int
main(void)
{
char buffer[STATION_SIZE+TEMPERATURE_SIZE];
int fd, keep_going;
struct sockaddr_in address;
// Create a IP4/UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address (of this host)
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(TEMPERATURE_PORT);
address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple
// Bind the socket to the address
bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr));
keep_going = 1;
while (keep_going)
{
// Receive the message (we don't care about the address of the sender)
recvfrom(fd, buffer, STATION_SIZE+TEMPERATURE_SIZE, 0, NULL, NULL) ;
if (buffer[3] == '!')
{
keep_going = 0;
}
else
{
write(STDOUT_FILENO, "Report from ", 12);
write(STDOUT_FILENO, buffer, STATION_SIZE);
write(STDOUT_FILENO, ": ", 2);
write(STDOUT_FILENO, buffer+STATION_SIZE, TEMPERATURE_SIZE);
write(STDOUT_FILENO, "\n\n", 2);
}
}
close(fd);
}
sockaddr:
struct sockaddr_in destination; memset(&destination, 0, sizeof(struct sockaddr_in)); destination.sin_family = AF_INET; inet_pton(AF_INET, RECEIVER_ADDRESS, &(destination.sin_addr)); destination.sin_port = htons(RECEIVER_PORT);
ssize_t sendto(int fd, const void *buffer, size_t buflen, int flags, const struct sockaddr *dest_addr, socklen_t *addrlen)
fd
|
The file descriptor of the UDP socket |
buffer
|
The datagram's payload |
length
|
The length of the payload |
flags
|
Flags (often 0) |
dest_addr
|
The address to send the datagram to |
addrlen
|
The length of the destination address |
| Return | The number of bytes sent on success; -1 on error |
#include <arpa/inet.h> // For byte order conversions
#include <string.h> // For memset()
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
int
main(int argc, char *argv[])
{
char buffer[STATION_SIZE+TEMPERATURE_SIZE];
char station[] = "JMU";
char temperature[TEMPERATURE_SIZE+1];
int fd, keep_going;
ssize_t input_length;
struct sockaddr_in destination;
if (argc > 1) strncpy(station, argv[1], STATION_SIZE);
// Create a IP4/UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address of the receiver
memset(&destination, 0, sizeof(struct sockaddr_in));
destination.sin_family = AF_INET;
inet_pton(AF_INET, "134.126.125.234", &(destination.sin_addr));
destination.sin_port = htons(TEMPERATURE_PORT);
keep_going = 1;
while (keep_going)
{
write(STDOUT_FILENO, "Temperature (or [Enter] to QUIT): ", 35);
// Clear the outgoing payload
memset(buffer, 0, STATION_SIZE+TEMPERATURE_SIZE);
// Populate the outgoing payload
strncpy(buffer, station, 3);
input_length = read(STDIN_FILENO, temperature, TEMPERATURE_SIZE+1);
if (input_length > 1)
{
strncpy(buffer+3, temperature, input_length-1);
}
else
{
strncpy(buffer+3, "!!!!!", 5);
keep_going = 0;
}
// Send the datagram
sendto(fd, buffer, STATION_SIZE+TEMPERATURE_SIZE, 0,
(struct sockaddr *)&destination, sizeof(destination)) ;
}
close(fd);
}
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
int
main(void)
{
char in[STATION_SIZE], out[TEMPERATURE_SIZE];
int fd;
struct sockaddr_in address, client_address;
socklen_t client_length = sizeof(struct sockaddr);
// Create an IP4/UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address of this host
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(FORECAST_PORT);
address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple
// Bind the socket to the address
bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr));
// Process requests
while (1)
{
// Receive the request
recvfrom(fd, in, STATION_SIZE, 0,
(struct sockaddr *)&client_address, &client_length);
// Send the response
memset(&out, 0, TEMPERATURE_SIZE);
sprintf(out, "%5.1f", forecast_for(in));
sendto(fd, out, TEMPERATURE_SIZE, 0,
(struct sockaddr *)&client_address, client_length);
}
close(fd);
}
#include <arpa/inet.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
int
main(int argc, char *argv[])
{
char in[TEMPERATURE_SIZE];
char out[] = "JMU";
int fd;
struct sockaddr_in server_address;
if (argc > 1) strncpy(out, argv[1], STATION_SIZE);
// Create an IP4/UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address of the server
memset(&server_address, 0, sizeof(struct sockaddr_in));
server_address.sin_family = AF_INET;
inet_pton(AF_INET, "134.126.125.234", &(server_address.sin_addr));
server_address.sin_port = htons(FORECAST_PORT);
// Send the request
sendto(fd, out, STATION_SIZE, 0,
(struct sockaddr *)&server_address, sizeof(server_address)) ;
// Receive the response
recvfrom(fd, in, TEMPERATURE_SIZE, 0, NULL, NULL);
// Display the respons
write(STDOUT_FILENO, "Forecast: ", 10);
write(STDOUT_FILENO, in, TEMPERATURE_SIZE);
write(STDOUT_FILENO, "\n", 1);
close(fd);
}
struct for a Binary Message#ifndef WEATHER_H
#define WEATHER_H
#define FORECAST_PORT 22801
#define RANGE_PORT 22802
#define TEMPERATURE_PORT 22807
#define TEMPERATURE_SIZE 5
#define STATION_SIZE 3
struct range {
uint16_t low;
uint16_t high;
};
float
forecast_for(char *station);
void
hton_range(const struct range *h, struct range *n);
void
ntoh_range(const struct range *n, struct range *h);
#endif
#include <arpa/inet.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
int
main(void)
{
char in[STATION_SIZE];
int fd;
struct range current, out;
struct sockaddr_in address, client_address;
socklen_t client_length = sizeof(struct sockaddr);
// Create a IP4/UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address (of this host)
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(RANGE_PORT);
address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple
// Bind the socket to the address
bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr));
// Process requests
while (1)
{
// Receive the request
recvfrom(fd, in, STATION_SIZE, 0,
(struct sockaddr *)&client_address, &client_length);
// Create the response
current.low = (uint16_t)forecast_for(in);
current.high = (uint16_t)forecast_for(in);
// Convert the respons to network byte order
hton_range(¤t, &out);
// Send the response
sendto(fd, &out, sizeof(struct range), 0,
(struct sockaddr *)&client_address, client_length);
}
close(fd);
}
#include <arpa/inet.h> // For byte order conversions
#include <stdio.h>
#include <string.h> // For memset()
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
int
main(int argc, char *argv[])
{
char out[] = "JMU";
int fd;
struct range current, in;
struct sockaddr_in server_address;
if (argc > 1) strncpy(out, argv[1], STATION_SIZE);
// Create a IP4/UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address of the server
memset(&server_address, 0, sizeof(struct sockaddr_in));
server_address.sin_family = AF_INET;
inet_pton(AF_INET, "134.126.125.234", &(server_address.sin_addr));
server_address.sin_port = htons(RANGE_PORT);
// Send the request
sendto(fd, out, STATION_SIZE, 0,
(struct sockaddr *)&server_address, sizeof(server_address)) ;
// Receive the response
recvfrom(fd, &in, TEMPERATURE_SIZE, 0, NULL, NULL);
// Convert from network byte order to host byte order
ntoh_range(&in, ¤t);
// DIsplay the converted response
printf("Low: %d\n", current.low);
printf("High: %d\n", current.high);
close(fd);
}
#include <arpa/inet.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
int
main(void)
{
char in[STATION_SIZE], out[TEMPERATURE_SIZE];
int ifd, ofd, pid;
struct sockaddr_in address, client_address;
socklen_t client_length = sizeof(struct sockaddr);
// Create an IP4/UDP socket
ifd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address of this host
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(FORECAST_PORT);
address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple
// Bind the socket to the address
bind(ifd, (struct sockaddr *)&address, sizeof(struct sockaddr));
// Handle requests (each in its own child process)
while (1)
{
// Receive the request
recvfrom(ifd, in, STATION_SIZE, 0,
(struct sockaddr *)&client_address, &client_length);
// Create the child process
pid = fork();
if (pid == 0)
{
// Close the child's copy of the incoming socket
close (ifd);
// Send the response
memset(&out, 0, TEMPERATURE_SIZE);
sprintf(out, "%5.1f", forecast_for(in));
ofd = socket(AF_INET, SOCK_DGRAM, 0);
sendto(ofd, out, TEMPERATURE_SIZE, 0,
(struct sockaddr *)&client_address, client_length);
close(ofd);
exit(0);
}
}
close(ifd);
}
#include <arpa/inet.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include "weather.h"
// The arguments needed to send a response
struct thread_arguments {
char station[STATION_SIZE];
struct sockaddr client_address;
socklen_t client_length;
};
// The entry point for the threads
static void
*send_response(void *arg)
{
char out[TEMPERATURE_SIZE];
int fd;
struct thread_arguments *args;
// Cast the arguments
args = (struct thread_arguments *)arg;
memset(&out, 0, TEMPERATURE_SIZE);
sprintf(out, "%5.1f", forecast_for(args->station));
fd = socket(AF_INET, SOCK_DGRAM, 0);
sendto(fd, out, TEMPERATURE_SIZE, 0, &(args->client_address), args->client_length);
close(fd);
// Free the memory used by the arguments
// (Caller Allocates/Callee Frees)
free(args);
return NULL;
}
int
main(void)
{
char in[STATION_SIZE];
int fd;
pthread_t helper;
struct sockaddr_in address, client_address;
struct thread_arguments *args;
socklen_t client_length = sizeof(struct sockaddr);
// Create an IP4/UDP socket
fd = socket(AF_INET, SOCK_DGRAM, 0);
// Initialize the address of this host
memset(&address, 0, sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(FORECAST_PORT);
address.sin_addr.s_addr = htonl(INADDR_ANY); // In case the host has multiple
// Bind the socket to the address
bind(fd, (struct sockaddr *)&address, sizeof(struct sockaddr));
// Process requests
while (1)
{
// Receive the request
recvfrom(fd, in, STATION_SIZE, 0,
(struct sockaddr *)&client_address, &client_length);
// Make a copy of the message and the client address
// for the thread that will handle the response
// (Caller Allocates/Callee Frees)
args = (struct thread_arguments *)malloc(sizeof(struct thread_arguments));
strncpy(args->station, in, STATION_SIZE);
memcpy(&(args->client_address), &client_address, client_length);
args->client_length = client_length;
// Create a thread to handle the response
pthread_create(&helper, NULL, send_response, (void *)args);
pthread_detach(helper);
}
close(fd);
}
int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
fd
|
The file descriptor of the UDP socket |
level
|
SOL_SOCKET, IPPROTO_IP, ... |
optname
|
The option to set |
optval
|
The value of the option |
optlen
|
The size of the optval argument |
| Return | 0 on success; -1 on error |
SO_SNDTIMEO and SO_RCVTIMEO
allow you to set timeouts (i.e., how long a call will
block before failing)SO_LINGER allows the socket to delay closing if
there are data to sendSO_REUSEADDR and SO_REUSEPORT
allow you to re-use an address and/or port even if they
are already bound (which can be useful when a server
fails and must be restarted)SO_RCVBUF and SO_SNDBUF allow you
to change buffer sizesstruct timeval timeout; timeout.tv_sec = 1; timeout.tv_usec = 0; setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(struct timeval));