第十一章 名字与地址转换:
#include <netdb.h>
struct hostnet * gethostbyname(const char * hostname);
error return NULL and set h_errno
struct hostnet {
char * h_name; /* official (canonical) name of host */
char ** h_aliases; /* alias name */
int h_addrtype; /* host addr type: AF_INET */
int h_length; /* length of address: 4 */
char ** h_addr_list; /* IPv4 addrs */
};
h_errno:
HOST_NOT_FOUND, TRY_AGAIN, NO_RECOVERY, NO_DATA(NO_ADDRESS)
#include <netdb.h>
struct hostnet * gethostbyaddr(const char * addr, socklen_t len, int family);
error return NULL and set h_errno
addr:
real type is struct in_addr
family:
AF_INET
len:
4, sizeof(struct in_addr)
#include <netdb.h>
struct servent * getservbyname(const char * servname, const char * protoname);
error return NULL
struct servent {
char * s_name; /* official service name */
char ** s_aliases; /* alias list */
int s_port; /* network byte order */
char * s_proto; /* protocol to use */
};
protoname:
"tcp", "udp", NULL
#include <netdb.h>
struct servent * getservbyport(int port, const_char * protoname);
error return NULL
port:
network byte order
protoname:
"tcp", "udp", NULL
#include <netdb.h>
int getaddrinfo(const char * hostname, const char * service,
const struct addrinfo * hints, struct addrinfo ** result);
success return 0, failed return error(EAI_xxx)
error:
EAI_AGAIN, EAI_BADFLAGS, EAI_FAIL, EAI_FAMILY, EAI_MEMORY,
EAI_NONAME, EAI_OVERFLOW, EAI_SERVICE, EAI_SOCKTYPE, EAI_SYSTEM
struct addrinfo {
int ai_flags;
int ai_family;
int ai_socktype;
int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
socklen_t ai_addrlen; /* length of ai_addr */
char * ai_canonname;
struct sockaddr * ai_addr;
struct addrinfo * ai_next;
};
hints only can set: ai_flags, ai_family, ai_socktype, ai_protocol
ai_flags:
AI_PASSIVE, AI_CANONNAME, AI_NUMERICHOST, AI_NUMERICSERV,
AI_V4MAPPED, AI_ALL, AI_ADDRCONFIG
#include <netdb.h>
const char * gai_strerror(int error);
#include <netdb.h>
void freeaddrinfo(struct addrinfo * ai);
some hostname:
0::0, 0.0.0.0; 0::1, 127.0.0.1
#include <netdb.h>
int getnameinfo(const struct sockaddr * sockaddr, socklen_t addrlen,
char * host, socklen_t hostlen,
char * serv, socklen_t servlen, int flags);
success return 0, failed return error(EAI_xxx)
flags:
NI_DGRAM, NI_NAMEREQD, NI_NOFQDN,
NI_NUMERICHOST, NI_NUMERICSCOPE, NI_NUMERICSERV
#include <netdb.h>
struct hostent * gethostbyname_r(const char * hostname,
struct hostnet * result,
char * buf, int buflen, int * h_errnop);
error return NULL
buflen should >= 8192
struct hostent * gethostbyaddr_r(const char * addr, int len, int type,
struct hostnet * result,
char * buf, int buflen, int * h_errnop);
error return NULL
buflen should >= 8192
other functions:
getXXXent, setXXXent, endXXXent
XXX:host, net, proto, serv
getnetbyaddr, getnetbyname,
getprotobyname, getprotobynumber
示例:
#include <netdb.h>
#include "err_exit.h"
int
main(int argc, char ** argv)
{
char * ptr;
char ** pptr;
char str[INET_ADDRSTRLEN];
struct hostent * hptr;
while (--argc > 0) {
ptr = *++argv;
if ((hptr = gethostbyname(ptr)) == NULL) {
printf("gethostbyname error for host: %s: %s\n",
ptr, hstrerror(h_errno));
continue;
}
printf("official hostname: %s\n", hptr->h_name);
for (pptr = hptr->h_aliases; *pptr != NULL; ++pptr) {
printf("\talias: %s\n", *pptr);
}
switch (hptr->h_addrtype)
{
case AF_INET:
{
pptr = hptr->h_addr_list;
for (; *pptr != NULL; ++pptr) {
if (inet_ntop(hptr->h_addrtype, *pptr,
str, sizeof(str)) == NULL) {
err_exit("inet_ntop error");
}
printf("\taddress: %s\n", str);
}
break;
}
default:
{
err_exit("unknown address type");
break;
}
}
}
exit(0);
}
#include <netdb.h>
#include "err_exit.h"
#include "sock_ntop.h"
#define MAXLINE 4096
int
main(int argc, char ** argv)
{
int sockfd;
int n;
char * paddr;
char recvline[MAXLINE + 1];
struct sockaddr_in servaddr;
struct in_addr ** pptr;
struct in_addr * inetaddrp[2];
struct in_addr inetaddr;
struct hostent * hp;
struct servent * sp;
if (argc != 3) {
printf("usage: daytimetcpcli1 <hostname> <service>\n");
exit(1);
}
if ((hp = gethostbyname(argv[1])) == NULL) {
if (inet_aton(argv[1], &inetaddr) <= 0) {
printf("hostname error for %s: %s\n", argv[1], hstrerror(h_errno));
exit(1);
}
else {
inetaddrp[0] = &inetaddr;
inetaddrp[1] = NULL;
pptr = inetaddrp;
}
}
else {
pptr = (struct in_addr **)hp->h_addr_list;
}
if ((sp = getservbyname(argv[2], "tcp")) == NULL) {
printf("gethostbyname error for host: %s: %s\n",
argv[2], hstrerror(h_errno));
exit(1);
}
for (; *pptr != NULL; ++pptr) {
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
err_exit("socket error");
}
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = sp->s_port;
memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
if ((paddr = sock_ntop((struct sockaddr *)&servaddr,
sizeof(servaddr))) == NULL) {
err_exit("sock_ntop error");
}
printf("trying %s\n", paddr);
if (connect(sockfd, (struct sockaddr *)&servaddr,
sizeof(servaddr)) == 0) {
break; /* success */
}
printf("connect error: %s\n", strerror(errno));
if (close(sockfd) == -1) {
err_exit("close error");
}
}
if (*pptr == NULL) {
printf("unable to connect");
exit(1);
}
while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = '\0'; /* null terminate */
if (fputs(recvline, stdout) == EOF) {
err_exit("fputs error");
}
}
if (n < 0) {
err_exit("read error");
}
exit(0);
}
#include <stdio.h>
#include <netdb.h>
#include <strings.h>
struct addrinfo *
host_serv(const char * host, const char * serv, int family, int socktype)
{
int n;
struct addrinfo hints;
struct addrinfo * res;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_CANONNAME; /* always return canonical name */
hints.ai_family = family; /* AF_UNSPEC, AF_INET, AF_INET6, etc. */
hints.ai_socktype = socktype; /* 0, SOCK_STREAM, SOCK_DGRAM, etc. */
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
printf("host_serv error for %s, %s: %s\n",
(host == NULL) ? "(no hostname)" : host,
(serv == NULL) ? "(no servname)" : serv,
gai_strerror(n));
exit(1);
}
return(res); /* return pointer to first on linked list */
}
#include <netdb.h>
#include <strings.h>
#include "err_exit.h"
#define LISTENQ 1024
int
tcp_listen(const char * host, const char * serv, socklen_t * addrlenp)
{
int listenfd;
int n;
const int on = 1;
struct addrinfo hints;
struct addrinfo * res;
struct addrinfo * ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
printf("host_serv error for %s, %s: %s\n",
(host == NULL) ? "(no hostname)" : host,
(serv == NULL) ? "(no servname)" : serv,
gai_strerror(n));
exit(1);
}
ressave = res;
do {
listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (listenfd == -1) {
continue; /* error, try next one */
}
if (setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR,
&on, sizeof(on)) == -1) {
err_exit("setsockopt error");
}
if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0) {
break; /* success */
}
/* bind error, close and try next one */
if (close(listenfd) == -1) {
err_exit("close error");
}
} while ((res = res->ai_next) != NULL);
if (res == NULL) { /* errno from final socket() or bind() */
printf("tcp_listen error for %s, %s\n", host, serv);
exit(1);
}
if (listen(listenfd, LISTENQ) == -1) {
err_exit("listen error");
}
if (addrlenp != NULL) {
*addrlenp = res->ai_addrlen; /* return size of protocol address */
}
freeaddrinfo(ressave);
return(listenfd);
}
#include <netdb.h>
#include <strings.h>
#include "err_exit.h"
int
tcp_connect(const char * host, const char * serv)
{
int sockfd;
int n;
struct addrinfo hints;
struct addrinfo * res;
struct addrinfo * ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
printf("host_serv error for %s, %s: %s\n",
(host == NULL) ? "(no hostname)" : host,
(serv == NULL) ? "(no servname)" : serv,
gai_strerror(n));
exit(1);
}
ressave = res;
do {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd == -1) {
continue; /* ignore this one */
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
break; /* success */
}
if (close(sockfd) == -1) {
err_exit("close error");
}
} while ((res = res->ai_next) != NULL);
freeaddrinfo(ressave);
if (res == NULL) { /* errno set from final connect() */
printf("tcp_connect error for %s, %s\n", host, serv);
exit(1);
}
return(sockfd);
}
#include <time.h>
#include <netdb.h>
#include "err_exit.h"
#include "sock_ntop.h"
#include "tcp_listen.h"
#define MAXLINE 4096
int
main(int argc, char ** argv)
{
int n;
int listenfd;
int connfd;
socklen_t len;
socklen_t addrlen;
char buff[MAXLINE];
time_t ticks;
struct sockaddr_storage cliaddr;
if (argc == 2) {
listenfd = tcp_listen(NULL, argv[1], &addrlen);
}
else if (argc == 3) {
listenfd = tcp_listen(argv[1], argv[2], &addrlen);
}
else {
printf("usage: daytimetcpsrv2 [ <host> ] <service or port>\n");
exit(1);
}
for ( ; ; ) {
len = sizeof(cliaddr);
if ((connfd = accept(listenfd, (struct sockaddr *)&cliaddr,
&len)) == -1) {
err_exit("accept error");
}
printf("connection from %s\n",
sock_ntop((struct sockaddr *)&cliaddr, len));
ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
n = strlen(buff);
if (write(connfd, buff, n) != n) {
err_exit("write error");
}
if (close(connfd) == -1) {
err_exit("close error");
}
}
}
#include <netdb.h>
#include "err_exit.h"
#include "sock_ntop.h"
#include "tcp_connect.h"
#define MAXLINE 4096
int
main(int argc, char ** argv)
{
int sockfd;
int n;
char * paddr;
char recvline[MAXLINE + 1];
socklen_t len;
struct sockaddr_storage ss;
if (argc != 3) {
printf("usage: daytimetcpcli <hostname/IPaddress> <service/port#>\n");
exit(1);
}
sockfd = tcp_connect(argv[1], argv[2]);
len = sizeof(ss);
if (getpeername(sockfd, (struct sockaddr *)&ss, &len) == -1) {
err_exit("getpeername error");
}
if ((paddr = sock_ntop((struct sockaddr *)&ss, len)) == NULL) {
err_exit("sock_ntop error");
}
printf("connected to %s\n", paddr);
while ((n = read(sockfd, recvline, MAXLINE)) > 0) {
recvline[n] = '\0'; /* null terminate */
if (fputs(recvline, stdout) == EOF) {
err_exit("fputs error");
}
}
if (n < 0) {
err_exit("read error");
}
exit(0);
}
#include <netdb.h>
#include <strings.h>
#include "err_exit.h"
int
udp_client(const char * host, const char * serv,
struct sockaddr ** saptr, socklen_t * lenp)
{
int sockfd;
int n;
struct addrinfo hints;
struct addrinfo * res;
struct addrinfo * ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
printf("host_serv error for %s, %s: %s\n",
(host == NULL) ? "(no hostname)" : host,
(serv == NULL) ? "(no servname)" : serv,
gai_strerror(n));
exit(1);
}
ressave = res;
do {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd != -1) {
break; /* success */
}
} while ((res = res->ai_next) != NULL);
if (res == NULL) { /* errno set from final socket() */
printf("udp_client error for %s, %s\n", host, serv);
}
if ((*saptr = (struct sockaddr *)malloc(res->ai_addrlen)) == NULL) {
err_exit("malloc error");
}
memcpy(*saptr, res->ai_addr, res->ai_addrlen);
if (lenp != NULL) {
*lenp = res->ai_addrlen;
}
freeaddrinfo(ressave);
return(sockfd);
}
#include <netdb.h>
#include <strings.h>
#include "err_exit.h"
int
udp_server(const char * host, const char * serv, socklen_t * addrlenp)
{
int sockfd;
int n;
struct addrinfo hints;
struct addrinfo * res;
struct addrinfo * ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
printf("host_serv error for %s, %s: %s\n",
(host == NULL) ? "(no hostname)" : host,
(serv == NULL) ? "(no servname)" : serv,
gai_strerror(n));
exit(1);
}
ressave = res;
do {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd == -1) {
continue; /* error - try next one */
}
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
break; /* success */
}
if (close(sockfd) == -1) { /* bind error - close and try next one */
err_exit("close error");
}
} while ((res = res->ai_next) != NULL);
if (res == NULL) { /* errno from final socket() or bind() */
printf("udp_server error for %s, %s\n", host, serv);
exit(1);
}
if (addrlenp != NULL) {
*addrlenp = res->ai_addrlen; /* return size of protocol address */
}
freeaddrinfo(ressave);
return(sockfd);
}
#include <netdb.h>
#include <strings.h>
#include "err_exit.h"
int
udp_connect(const char * host, const char * serv)
{
int sockfd;
int n;
struct addrinfo hints;
struct addrinfo * res;
struct addrinfo * ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0) {
printf("host_serv error for %s, %s: %s\n",
(host == NULL) ? "(no hostname)" : host,
(serv == NULL) ? "(no servname)" : serv,
gai_strerror(n));
exit(1);
}
ressave = res;
do {
sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd == -1) {
continue; /* ignore this one */
}
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0) {
break; /* success */
}
if (close(sockfd) == -1) {
err_exit("close error");
}
} while ((res = res->ai_next) != NULL);
if (res == NULL) { /* errno set from final connect() */
printf("udp_connect error for %s, %s\n", host, serv);
}
freeaddrinfo(ressave);
return(sockfd);
}
#include <time.h>
#include <netdb.h>
#include "err_exit.h"
#include "sock_ntop.h"
#include "udp_server.h"
#define MAXLINE 4096
int
main(int argc, char ** argv)
{
int sockfd;
ssize_t n;
char * paddr;
char buff[MAXLINE];
time_t ticks;
socklen_t len;
struct sockaddr_storage cliaddr;
if (argc == 2) {
sockfd = udp_server(NULL, argv[1], NULL);
}
else if (argc == 3) {
sockfd = udp_server(argv[1], argv[2], NULL);
}
else {
printf("usage: daytimeudpsrv [ <host> ] <service or port>\n");
exit(1);
}
for ( ; ; ) {
len = sizeof(cliaddr);
n = recvfrom(sockfd, buff, MAXLINE, 0,
(struct sockaddr *)&cliaddr, &len);
if ((paddr = sock_ntop((struct sockaddr *)&cliaddr, len)) == NULL) {
printf("sock_ntop error");
}
printf("datagram from %s\n", paddr);
ticks = time(NULL);
snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks));
n = strlen(buff);
if (sendto(sockfd, buff, n, 0, (struct sockaddr *)&cliaddr, len) != n) {
err_exit("sendto error");
}
}
}
#include <netdb.h>
#include "err_exit.h"
#include "sock_ntop.h"
#include "udp_client.h"
#define MAXLINE 4096
int
main(int argc, char ** argv)
{
int sockfd;
int n;
char * paddr;
char recvline[MAXLINE + 1];
socklen_t salen;
struct sockaddr * sa;
if (argc != 3) {
printf("usage: daytimeudpcli1 <hostname/IPaddress> <service/port#>\n");
exit(1);
}
sockfd = udp_client(argv[1], argv[2], &sa, &salen);
if ((paddr = sock_ntop(sa, salen)) == NULL) {
err_exit("sock_ntop error");
}
printf("sending to %s\n", paddr);
if (sendto(sockfd, "", 1, 0, sa, salen) != 1) { /* send 1-byte datagram */
err_exit("sendto error");
}
if (n = recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL) < 0) {
err_exit("recvfrom error");
}
recvline[n] = '\0'; /* null terminate */
if (fputs(recvline, stdout) == EOF) {
err_exit("fputs error");
}
exit(0);
}