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));