Created
February 4, 2017 16:12
-
-
Save saxbophone/f770e86ceff9d488396c0c32d47b757e to your computer and use it in GitHub Desktop.
UDP C socket programming example, from the Linux man pages (man getaddrinfo)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* client.c */ | |
#include <sys/types.h> | |
#include <sys/socket.h> | |
#include <netdb.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string.h> | |
#define BUF_SIZE 500 | |
int main(int argc, char *argv[]) { | |
struct addrinfo hints; | |
struct addrinfo *result, *rp; | |
int sfd, s, j; | |
size_t len; | |
ssize_t nread; | |
char buf[BUF_SIZE]; | |
if (argc < 3) { | |
fprintf(stderr, "Usage: %s host port msg...\n", argv[0]); | |
exit(EXIT_FAILURE); | |
} | |
/* Obtain address(es) matching host/port */ | |
memset(&hints, 0, sizeof(struct addrinfo)); | |
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ | |
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ | |
hints.ai_flags = 0; | |
hints.ai_protocol = 0; /* Any protocol */ | |
s = getaddrinfo(argv[1], argv[2], &hints, &result); | |
if (s != 0) { | |
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); | |
exit(EXIT_FAILURE); | |
} | |
/* getaddrinfo() returns a list of address structures. | |
Try each address until we successfully connect(2). | |
If socket(2) (or connect(2)) fails, we (close the socket | |
and) try the next address. */ | |
for (rp = result; rp != NULL; rp = rp->ai_next) { | |
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); | |
if (sfd == -1) | |
continue; | |
if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1) | |
break; /* Success */ | |
close(sfd); | |
} | |
if (rp == NULL) { /* No address succeeded */ | |
fprintf(stderr, "Could not connect\n"); | |
exit(EXIT_FAILURE); | |
} | |
freeaddrinfo(result); /* No longer needed */ | |
/* Send remaining command-line arguments as separate | |
datagrams, and read responses from server */ | |
for (j = 3; j < argc; j++) { | |
len = strlen(argv[j]) + 1; | |
/* +1 for terminating null byte */ | |
if (len + 1 > BUF_SIZE) { | |
fprintf(stderr, "Ignoring long message in argument %d\n", j); | |
continue; | |
} | |
if (write(sfd, argv[j], len) != len) { | |
fprintf(stderr, "partial/failed write\n"); | |
exit(EXIT_FAILURE); | |
} | |
nread = read(sfd, buf, BUF_SIZE); | |
if (nread == -1) { | |
perror("read"); | |
exit(EXIT_FAILURE); | |
} | |
printf("Received %zd bytes: %s\n", nread, buf); | |
} | |
exit(EXIT_SUCCESS); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* server.c */ | |
#include <sys/types.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <unistd.h> | |
#include <string.h> | |
#include <sys/socket.h> | |
#include <netdb.h> | |
#define BUF_SIZE 500 | |
int main(int argc, char *argv[]) { | |
struct addrinfo hints; | |
struct addrinfo *result, *rp; | |
int sfd, s; | |
struct sockaddr_storage peer_addr; | |
socklen_t peer_addr_len; | |
ssize_t nread; | |
char buf[BUF_SIZE]; | |
if (argc != 2) { | |
fprintf(stderr, "Usage: %s port\n", argv[0]); | |
exit(EXIT_FAILURE); | |
} | |
memset(&hints, 0, sizeof(struct addrinfo)); | |
hints.ai_family = AF_UNSPEC; /* Allow IPv4 or IPv6 */ | |
hints.ai_socktype = SOCK_DGRAM; /* Datagram socket */ | |
hints.ai_flags = AI_PASSIVE; /* For wildcard IP address */ | |
hints.ai_protocol = 0; /* Any protocol */ | |
hints.ai_canonname = NULL; | |
hints.ai_addr = NULL; | |
hints.ai_next = NULL; | |
s = getaddrinfo(NULL, argv[1], &hints, &result); | |
if (s != 0) { | |
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s)); | |
exit(EXIT_FAILURE); | |
} | |
/* getaddrinfo() returns a list of address structures. | |
Try each address until we successfully bind(2). | |
If socket(2) (or bind(2)) fails, we (close the socket | |
and) try the next address. */ | |
for (rp = result; rp != NULL; rp = rp->ai_next) { | |
sfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol); | |
if (sfd == -1) | |
continue; | |
if (bind(sfd, rp->ai_addr, rp->ai_addrlen) == 0) | |
break; /* Success */ | |
close(sfd); | |
} | |
if (rp == NULL) { /* No address succeeded */ | |
fprintf(stderr, "Could not bind\n"); | |
exit(EXIT_FAILURE); | |
} | |
freeaddrinfo(result); /* No longer needed */ | |
/* Read datagrams and echo them back to sender */ | |
for (;;) { | |
peer_addr_len = sizeof(struct sockaddr_storage); | |
nread = recvfrom( | |
sfd, buf, BUF_SIZE, 0, (struct sockaddr *) &peer_addr, &peer_addr_len | |
); | |
if (nread == -1) | |
continue; /* Ignore failed request */ | |
char host[NI_MAXHOST], service[NI_MAXSERV]; | |
s = getnameinfo( | |
(struct sockaddr *) &peer_addr, | |
peer_addr_len, | |
host, | |
NI_MAXHOST, | |
service, | |
NI_MAXSERV, | |
NI_NUMERICSERV | |
); | |
if (s == 0) | |
printf("Received %zd bytes from %s:%s\n", nread, host, service); | |
else | |
fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s)); | |
if ( | |
sendto( | |
sfd, | |
buf, | |
nread, | |
0, | |
(struct sockaddr *) &peer_addr, | |
peer_addr_len | |
) != nread | |
) { | |
fprintf(stderr, "Error sending response\n"); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment