jason0401 发表于 2015-11-24 07:44:19

Unix网络编程代码 第11章 名字与地址转换

第11章 名字与地址转换

11.3 gethostbyname函数

#define _BSD_SOURCE
#include<stdarg.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netdb.h>
#defineMAXLINE4096/* max text line length */
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys(&quot;inet_pton error for %s&quot;, strptr);/* errno set */
else if (n == 0)
err_quit(&quot;inet_pton error for %s&quot;, strptr);/* errno not set */
/* nothing to return */
}
void err_msg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
return;
}
const char *Inet_ntop(int family, const void *addrptr, char *strptr, size_t len)
{
const char *ptr;
if (strptr == NULL)/* check for old code */
err_quit(&quot;NULL 3rd argument to inet_ntop&quot;);
if ((ptr = inet_ntop(family, addrptr, strptr, len)) == NULL)
err_sys(&quot;inet_ntop error&quot;);/* sets errno */
return (ptr);
}
void err_ret(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
return;
}
int main(int argc, char **argv)
{
char *ptr, **pptr;
char str;
struct hostent *hptr;
while (--argc > 0) {
ptr = *++argv;
if ((hptr = gethostbyname(ptr)) == NULL) {
err_msg(&quot;gethostbyname error for host: %s: %s&quot;,
ptr, hstrerror(h_errno));
continue;
}
printf(&quot;official hostname: %s\n&quot;, hptr->h_name);
for (pptr = hptr->h_aliases; *pptr != NULL; pptr++)
printf(&quot;\talias: %s\n&quot;, *pptr);
switch (hptr->h_addrtype) {
case AF_INET:
pptr = hptr->h_addr_list;
for (; *pptr != NULL; pptr++)
printf(&quot;\taddress: %s\n&quot;,
Inet_ntop(hptr->h_addrtype, *pptr, str,
sizeof(str)));
break;
default:
err_ret(&quot;unknown address type&quot;);
break;
}
}
exit(0);
}

11.5 getservbyname和getservbyport函数

//时间获取客户端,使用gethostbyname 和 getservbyname.
#define _BSD_SOURCE
#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */
#include<stdarg.h>/* ANSI C header file */
#include<syslog.h>/* for syslog() */
#include<stdlib.h>
#include<errno.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/un.h>
#defineMAXLINE4096/* max text line length */
#defineSAstruct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
void Close(int fd)
{
if (close(fd) == -1)
err_sys(&quot;close error&quot;);
}
ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
if ((n = read(fd, ptr, nbytes)) == -1)
err_sys(&quot;read error&quot;);
return (n);
}
void Fputs(const char *ptr, FILE * stream)
{
if (fputs(ptr, stream) == EOF)
err_sys(&quot;fputs error&quot;);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys(&quot;socket error&quot;);
return (n);
}
char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char portstr;
static char str;/* Unix domain is largest */
switch (sa->sa_family) {
case AF_INET:{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
== NULL)
return (NULL);
if (ntohs(sin->sin_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;:%d&quot;,
ntohs(sin->sin_port));
strcat(str, portstr);
}
return (str);
}
/* end sock_ntop */
#ifdefIPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
str = '[';
if (inet_ntop
(AF_INET6, &sin6->sin6_addr, str + 1,
sizeof(str) - 1) == NULL)
return (NULL);
if (ntohs(sin6->sin6_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;]:%d&quot;,
ntohs(sin6->sin6_port));
strcat(str, portstr);
return (str);
}
return (str + 1);
}
#endif
#ifdefAF_UNIX
case AF_UNIX:{
struct sockaddr_un *unp = (struct sockaddr_un *)sa;
/* OK to have no pathname bound to the socket: happens on
every connect() unless client calls bind() first. */
if (unp->sun_path == 0)
strcpy(str, &quot;(no pathname bound)&quot;);
else
snprintf(str, sizeof(str), &quot;%s&quot;, unp->sun_path);
return (str);
}
#endif
#ifdefHAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), &quot;%*s (index %d)&quot;,
sdl->sdl_nlen, &sdl->sdl_data,
sdl->sdl_index);
else
snprintf(str, sizeof(str), &quot;AF_LINK, index=%d&quot;,
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
&quot;sock_ntop: unknown AF_xxx: %d, len %d&quot;, sa->sa_family,
salen);
return (str);
}
return (NULL);
}
char *Sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char *ptr;
if ((ptr = sock_ntop(sa, salen)) == NULL)
err_sys(&quot;sock_ntop error&quot;);/* inet_ntop() sets errno */
return (ptr);
}
void err_ret(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
return;
}
int main(int argc, char **argv)
{
int sockfd, n;
char recvline;
struct sockaddr_in servaddr;
struct in_addr **pptr;
struct in_addr *inetaddrp;
struct in_addr inetaddr;
struct hostent *hp;
struct servent *sp;
if (argc != 3)
err_quit(&quot;usage: daytimetcpcli1 <hostname> <service>&quot;);
if ((hp = gethostbyname(argv)) == NULL) {
if (inet_aton(argv, &inetaddr) == 0) {
err_quit(&quot;hostname error for %s: %s&quot;, argv,
hstrerror(h_errno));
} else {
inetaddrp = &inetaddr;
inetaddrp = NULL;
pptr = inetaddrp;
}
} else {
pptr = (struct in_addr **)hp->h_addr_list;
}
if ((sp = getservbyname(argv, &quot;tcp&quot;)) == NULL)
err_quit(&quot;getservbyname error for %s&quot;, argv);
for (; *pptr != NULL; pptr++) {
sockfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = sp->s_port;
memcpy(&servaddr.sin_addr, *pptr, sizeof(struct in_addr));
printf(&quot;trying %s\n&quot;,
Sock_ntop((SA *) & servaddr, sizeof(servaddr)));
if (connect(sockfd, (SA *) & servaddr, sizeof(servaddr)) == 0)
break;/* success */
err_ret(&quot;connect error&quot;);
close(sockfd);
}
if (*pptr == NULL)
err_quit(&quot;unable to connect&quot;);
while ((n = Read(sockfd, recvline, MAXLINE)) > 0) {
recvline = 0;/* null terminate */
Fputs(recvline, stdout);
}
exit(0);
}

11.12 tcp_connect函数

#define _POSIX_SOURCE
#include<strings.h>
#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */
#include<stdarg.h>/* ANSI C header file */
#include<syslog.h>/* for syslog() */
#include<stdlib.h>
#include<errno.h>
#include<stdio.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/un.h>
#defineMAXLINE4096/* max text line length */
#defineSAstruct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
void Close(int fd)
{
if (close(fd) == -1)
err_sys(&quot;close error&quot;);
}
int tcp_connect(const char *host, const char *serv)
{
int sockfd, n;
struct addrinfo hints, *res, *ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
err_quit(&quot;tcp_connect error for %s, %s: %s&quot;,
host, serv, gai_strerror(n));
ressave = res;
do {
sockfd =
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0)
continue;/* ignore this one */
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
break;/* success */
Close(sockfd);/* ignore this one */
} while ((res = res->ai_next) != NULL);
if (res == NULL)/* errno set from final connect() */
err_sys(&quot;tcp_connect error for %s, %s&quot;, host, serv);
freeaddrinfo(ressave);
return (sockfd);
}
int Tcp_connect(const char *host, const char *serv)
{
return (tcp_connect(host, serv));
}
void Getpeername(int fd, struct sockaddr *sa, socklen_t * salenptr)
{
if (getpeername(fd, sa, salenptr) < 0)
err_sys(&quot;getpeername error&quot;);
}
char *sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
{
static char str;/* Unix domain is largest */
switch (sa->sa_family) {
case AF_INET:{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
== NULL)
return (NULL);
return (str);
}
#ifdefIPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
if (inet_ntop
(AF_INET6, &sin6->sin6_addr, str,
sizeof(str)) == NULL)
return (NULL);
return (str);
}
#endif
#ifdefAF_UNIX
case AF_UNIX:{
struct sockaddr_un *unp = (struct sockaddr_un *)sa;
/* OK to have no pathname bound to the socket: happens on
every connect() unless client calls bind() first. */
if (unp->sun_path == 0)
strcpy(str, &quot;(no pathname bound)&quot;);
else
snprintf(str, sizeof(str), &quot;%s&quot;, unp->sun_path);
return (str);
}
#endif
#ifdefHAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), &quot;%*s&quot;,
sdl->sdl_nlen, &sdl->sdl_data);
else
snprintf(str, sizeof(str), &quot;AF_LINK, index=%d&quot;,
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
&quot;sock_ntop_host: unknown AF_xxx: %d, len %d&quot;,
sa->sa_family, salen);
return (str);
}
return (NULL);
}
char *Sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
{
char *ptr;
if ((ptr = sock_ntop_host(sa, salen)) == NULL)
err_sys(&quot;sock_ntop_host error&quot;);/* inet_ntop() sets errno */
return (ptr);
}
ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
if ((n = read(fd, ptr, nbytes)) == -1)
err_sys(&quot;read error&quot;);
return (n);
}
void Fputs(const char *ptr, FILE * stream)
{
if (fputs(ptr, stream) == EOF)
err_sys(&quot;fputs error&quot;);
}
int main(int argc, char **argv)
{
int sockfd, n;
char recvline;
socklen_t len;
struct sockaddr_storage ss;
if (argc != 3)
err_quit
(&quot;usage: daytimetcpcli <hostname/IPaddress> <service/port#>&quot;);
sockfd = Tcp_connect(argv, argv);
len = sizeof(ss);
Getpeername(sockfd, (SA *) & ss, &len);
printf(&quot;connected to %s\n&quot;, Sock_ntop_host((SA *) & ss, len));
while ((n = Read(sockfd, recvline, MAXLINE)) > 0) {
recvline = 0;/* null terminate */
Fputs(recvline, stdout);
}
exit(0);
}

11.13 tcp_listen函数

11.13.1 时间获取服务器程序

#define_POSIX_SOURCE
#include<strings.h>
#include<time.h>
#include<sys/socket.h>/* basic socket definitions */
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */
#include<stdarg.h>/* ANSI C header file */
#include<netdb.h>
#include<arpa/inet.h>
#include<sys/un.h>
#defineMAXLINE4096/* max text line length */
#defineLISTENQ1024/* 2nd argument to listen() */
#defineSAstruct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys(&quot;socket error&quot;);
return (n);
}
void Close(int fd)
{
if (close(fd) == -1)
err_sys(&quot;close error&quot;);
}
void Listen(int fd, int backlog)
{
char *ptr;
/*4can override 2nd argument with environment variable */
if ((ptr = getenv(&quot;LISTENQ&quot;)) != NULL)
backlog = atoi(ptr);
if (listen(fd, backlog) < 0)
err_sys(&quot;listen error&quot;);
}
int Accept(int fd, struct sockaddr *sa, socklen_t * salenptr)
{
int n;
again:if ((n = accept(fd, sa, salenptr)) < 0) {
#ifdefEPROTO
if (errno == EPROTO || errno == ECONNABORTED)
#else
if (errno == ECONNABORTED)
#endif
goto again;
else
err_sys(&quot;accept error&quot;);
}
return (n);
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
err_sys(&quot;bind error&quot;);
}
void Write(int fd, void *ptr, int nbytes)
{
if (write(fd, ptr, nbytes) != nbytes)
err_sys(&quot;write error&quot;);
}
void Setsockopt(int fd, int level, int optname, const void *optval,
socklen_t optlen)
{
if (setsockopt(fd, level, optname, optval, optlen) < 0)
err_sys(&quot;setsockopt error&quot;);
}
int tcp_listen(const char *host, const char *serv, socklen_t * addrlenp)
{
int listenfd, n;
const int on = 1;
struct addrinfo hints, *res, *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)
err_quit(&quot;tcp_listen error for %s, %s: %s&quot;,
host, serv, gai_strerror(n));
ressave = res;
do {
listenfd =
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (listenfd < 0)
continue;/* error, try next one */
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
break;/* success */
Close(listenfd);/* bind error, close and try next one */
} while ((res = res->ai_next) != NULL);
if (res == NULL)/* errno from final socket() or bind() */
err_sys(&quot;tcp_listen error for %s, %s&quot;, host, serv);
Listen(listenfd, LISTENQ);
if (addrlenp)
*addrlenp = res->ai_addrlen;/* return size of protocol address */
freeaddrinfo(ressave);
return (listenfd);
}
int Tcp_listen(const char *host, const char *serv, socklen_t * addrlenp)
{
return (tcp_listen(host, serv, addrlenp));
}
char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char portstr;
static char str;/* Unix domain is largest */
switch (sa->sa_family) {
case AF_INET:{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
== NULL)
return (NULL);
if (ntohs(sin->sin_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;:%d&quot;,
ntohs(sin->sin_port));
strcat(str, portstr);
}
return (str);
}
/* end sock_ntop */
#ifdefIPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
str = '[';
if (inet_ntop
(AF_INET6, &sin6->sin6_addr, str + 1,
sizeof(str) - 1) == NULL)
return (NULL);
if (ntohs(sin6->sin6_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;]:%d&quot;,
ntohs(sin6->sin6_port));
strcat(str, portstr);
return (str);
}
return (str + 1);
}
#endif
#ifdefAF_UNIX
case AF_UNIX:{
struct sockaddr_un *unp = (struct sockaddr_un *)sa;
/* OK to have no pathname bound to the socket: happens on
every connect() unless client calls bind() first. */
if (unp->sun_path == 0)
strcpy(str, &quot;(no pathname bound)&quot;);
else
snprintf(str, sizeof(str), &quot;%s&quot;, unp->sun_path);
return (str);
}
#endif
#ifdefHAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), &quot;%*s (index %d)&quot;,
sdl->sdl_nlen, &sdl->sdl_data,
sdl->sdl_index);
else
snprintf(str, sizeof(str), &quot;AF_LINK, index=%d&quot;,
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
&quot;sock_ntop: unknown AF_xxx: %d, len %d&quot;, sa->sa_family,
salen);
return (str);
}
return (NULL);
}
char *Sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char *ptr;
if ((ptr = sock_ntop(sa, salen)) == NULL)
err_sys(&quot;sock_ntop error&quot;);/* inet_ntop() sets errno */
return (ptr);
}
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t len;
char buff;
time_t ticks;
struct sockaddr_storage cliaddr;
if (argc != 2)
err_quit(&quot;usage: daytimetcpsrv1 <service or port#>&quot;);
listenfd = Tcp_listen(NULL, argv, NULL);
for (;;) {
len = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) & cliaddr, &len);
printf(&quot;connection from %s\n&quot;,
Sock_ntop((SA *) & cliaddr, len));
ticks = time(NULL);
snprintf(buff, sizeof(buff), &quot;%.24s\r\n&quot;, ctime(&ticks));
Write(connfd, buff, strlen(buff));
Close(connfd);
}
}

11.13.2 可指定协议的时间获取服务器程序

#define _POSIX_SOURCE
#include<strings.h>
#include<time.h>
#include<sys/socket.h>/* basic socket definitions */
#include<errno.h>
#include<string.h>
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */
#include<stdarg.h>/* ANSI C header file */
#include<netdb.h>
#include<arpa/inet.h>
#include<sys/un.h>
#defineMAXLINE4096/* max text line length */
#defineLISTENQ1024/* 2nd argument to listen() */
#defineSAstruct sockaddr
#define IPV6
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys(&quot;socket error&quot;);
return (n);
}
void Close(int fd)
{
if (close(fd) == -1)
err_sys(&quot;close error&quot;);
}
void Listen(int fd, int backlog)
{
char *ptr;
/*4can override 2nd argument with environment variable */
if ((ptr = getenv(&quot;LISTENQ&quot;)) != NULL)
backlog = atoi(ptr);
if (listen(fd, backlog) < 0)
err_sys(&quot;listen error&quot;);
}
int Accept(int fd, struct sockaddr *sa, socklen_t * salenptr)
{
int n;
again:if ((n = accept(fd, sa, salenptr)) < 0) {
#ifdefEPROTO
if (errno == EPROTO || errno == ECONNABORTED)
#else
if (errno == ECONNABORTED)
#endif
goto again;
else
err_sys(&quot;accept error&quot;);
}
return (n);
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
err_sys(&quot;bind error&quot;);
}
void Write(int fd, void *ptr, int nbytes)
{
if (write(fd, ptr, nbytes) != nbytes)
err_sys(&quot;write error&quot;);
}
void Setsockopt(int fd, int level, int optname, const void *optval,
socklen_t optlen)
{
if (setsockopt(fd, level, optname, optval, optlen) < 0)
err_sys(&quot;setsockopt error&quot;);
}
int tcp_listen(const char *host, const char *serv, socklen_t * addrlenp)
{
int listenfd, n;
const int on = 1;
struct addrinfo hints, *res, *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)
err_quit(&quot;tcp_listen error for %s, %s: %s&quot;,
host, serv, gai_strerror(n));
ressave = res;
do {
listenfd =
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (listenfd < 0)
continue;/* error, try next one */
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
break;/* success */
Close(listenfd);/* bind error, close and try next one */
} while ((res = res->ai_next) != NULL);
if (res == NULL)/* errno from final socket() or bind() */
err_sys(&quot;tcp_listen error for %s, %s&quot;, host, serv);
Listen(listenfd, LISTENQ);
if (addrlenp)
*addrlenp = res->ai_addrlen;/* return size of protocol address */
freeaddrinfo(ressave);
return (listenfd);
}
int Tcp_listen(const char *host, const char *serv, socklen_t * addrlenp)
{
return (tcp_listen(host, serv, addrlenp));
}
char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char portstr;
static char str;/* Unix domain is largest */
switch (sa->sa_family) {
case AF_INET:{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
== NULL)
return (NULL);
if (ntohs(sin->sin_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;:%d&quot;,
ntohs(sin->sin_port));
strcat(str, portstr);
}
return (str);
}
/* end sock_ntop */
#ifdefIPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
str = '[';
if (inet_ntop
(AF_INET6, &sin6->sin6_addr, str + 1,
sizeof(str) - 1) == NULL)
return (NULL);
if (ntohs(sin6->sin6_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;]:%d&quot;,
ntohs(sin6->sin6_port));
strcat(str, portstr);
return (str);
}
return (str + 1);
}
#endif
#ifdefAF_UNIX
case AF_UNIX:{
struct sockaddr_un *unp = (struct sockaddr_un *)sa;
/* OK to have no pathname bound to the socket: happens on
every connect() unless client calls bind() first. */
if (unp->sun_path == 0)
strcpy(str, &quot;(no pathname bound)&quot;);
else
snprintf(str, sizeof(str), &quot;%s&quot;, unp->sun_path);
return (str);
}
#endif
#ifdefHAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), &quot;%*s (index %d)&quot;,
sdl->sdl_nlen, &sdl->sdl_data,
sdl->sdl_index);
else
snprintf(str, sizeof(str), &quot;AF_LINK, index=%d&quot;,
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
&quot;sock_ntop: unknown AF_xxx: %d, len %d&quot;, sa->sa_family,
salen);
return (str);
}
return (NULL);
}
char *Sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char *ptr;
if ((ptr = sock_ntop(sa, salen)) == NULL)
err_sys(&quot;sock_ntop error&quot;);/* inet_ntop() sets errno */
return (ptr);
}
int main(int argc, char **argv)
{
int listenfd, connfd;
socklen_t len, addrlen;
char buff;
time_t ticks;
struct sockaddr_storage cliaddr;
if (argc == 2)
listenfd = Tcp_listen(NULL, argv, &addrlen);
else if (argc == 3)
listenfd = Tcp_listen(argv, argv, &addrlen);
else
err_quit(&quot;usage: daytimetcpsrv2 [ <host> ] <service or port>&quot;);
for (;;) {
len = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) & cliaddr, &len);
printf(&quot;connection from %s\n&quot;,
Sock_ntop((SA *) & cliaddr, len));
ticks = time(NULL);
snprintf(buff, sizeof(buff), &quot;%.24s\r\n&quot;, ctime(&ticks));
Write(connfd, buff, strlen(buff));
Close(connfd);
}
}

11.14 udp_client函数

11.14.1 协议无关的时间获取客户端程序

//udp时间获取客户端程序
#define_POSIX_SOURCE
#include<strings.h>
#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */
#include<stdarg.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/un.h>
#define IPV6
#defineMAXLINE4096/* max text line length */
#defineSAstruct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys(&quot;socket error&quot;);
return (n);
}
ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags,
struct sockaddr * sa, socklen_t * salenptr)
{
ssize_t n;
if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)
err_sys(&quot;recvfrom error&quot;);
return (n);
}
void Sendto(int fd, const void *ptr, size_t nbytes, int flags,
const struct sockaddr *sa, socklen_t salen)
{
if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)
err_sys(&quot;sendto error&quot;);
}
void Fputs(const char *ptr, FILE * stream)
{
if (fputs(ptr, stream) == EOF)
err_sys(&quot;fputs error&quot;);
}
void *Malloc(size_t size)
{
void *ptr;
if ((ptr = malloc(size)) == NULL)
err_sys(&quot;malloc error&quot;);
return (ptr);
}
int udp_client(const char *host, const char *serv, SA ** saptr,
socklen_t * lenp)
{
int sockfd, n;
struct addrinfo hints, *res, *ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
err_quit(&quot;udp_client error for %s, %s: %s&quot;,
host, serv, gai_strerror(n));
ressave = res;
do {
sockfd =
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd >= 0)
break;/* success */
} while ((res = res->ai_next) != NULL);
if (res == NULL)/* errno set from final socket() */
err_sys(&quot;udp_client error for %s, %s&quot;, host, serv);
*saptr = (SA *) Malloc(res->ai_addrlen);
memcpy(*saptr, res->ai_addr, res->ai_addrlen);
*lenp = res->ai_addrlen;
freeaddrinfo(ressave);
return (sockfd);
}
int Udp_client(const char *host, const char *serv, SA ** saptr,
socklen_t * lenptr)
{
return (udp_client(host, serv, saptr, lenptr));
}
char *sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
{
static char str;/* Unix domain is largest */
switch (sa->sa_family) {
case AF_INET:{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
== NULL)
return (NULL);
return (str);
}
#ifdefIPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
if (inet_ntop
(AF_INET6, &sin6->sin6_addr, str,
sizeof(str)) == NULL)
return (NULL);
return (str);
}
#endif
#ifdefAF_UNIX
case AF_UNIX:{
struct sockaddr_un *unp = (struct sockaddr_un *)sa;
/* OK to have no pathname bound to the socket: happens on
every connect() unless client calls bind() first. */
if (unp->sun_path == 0)
strcpy(str, &quot;(no pathname bound)&quot;);
else
snprintf(str, sizeof(str), &quot;%s&quot;, unp->sun_path);
return (str);
}
#endif
#ifdefHAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), &quot;%*s&quot;,
sdl->sdl_nlen, &sdl->sdl_data);
else
snprintf(str, sizeof(str), &quot;AF_LINK, index=%d&quot;,
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
&quot;sock_ntop_host: unknown AF_xxx: %d, len %d&quot;,
sa->sa_family, salen);
return (str);
}
return (NULL);
}
char *Sock_ntop_host(const struct sockaddr *sa, socklen_t salen)
{
char *ptr;
if ((ptr = sock_ntop_host(sa, salen)) == NULL)
err_sys(&quot;sock_ntop_host error&quot;);/* inet_ntop() sets errno */
return (ptr);
}
int main(int argc, char **argv)
{
int sockfd, n;
char recvline;
socklen_t salen;
struct sockaddr *sa;
if (argc != 3)
err_quit
(&quot;usage: daytimeudpcli1 <hostname/IPaddress> <service/port#>&quot;);
sockfd = Udp_client(argv, argv, &sa, &salen);
printf(&quot;sending to %s\n&quot;, Sock_ntop_host(sa, salen));
Sendto(sockfd, &quot;&quot;, 1, 0, sa, salen);/* send 1-byte datagram */
n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline = '\0';/* null terminate */
Fputs(recvline, stdout);
exit(0);
}

11.15 udp_connect函数

//udp时间获取客户端程序
#define _POSIX_SOURCE
#include<strings.h>
#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */
#include<stdarg.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<errno.h>
#include<arpa/inet.h>
#include<netdb.h>
#include<sys/un.h>
#include<unistd.h>
#define IPV6
#defineMAXLINE4096/* max text line length */
#defineSAstruct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys(&quot;socket error&quot;);
return (n);
}
ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags,
struct sockaddr * sa, socklen_t * salenptr)
{
ssize_t n;
if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)
err_sys(&quot;recvfrom error&quot;);
return (n);
}
void Sendto(int fd, const void *ptr, size_t nbytes, int flags,
const struct sockaddr *sa, socklen_t salen)
{
if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)
err_sys(&quot;sendto error&quot;);
}
void Fputs(const char *ptr, FILE * stream)
{
if (fputs(ptr, stream) == EOF)
err_sys(&quot;fputs error&quot;);
}
void Close(int fd)
{
if (close(fd) == -1)
err_sys(&quot;close error&quot;);
}
int udp_connect(const char *host, const char *serv)
{
int sockfd, n;
struct addrinfo hints, *res, *ressave;
bzero(&hints, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
err_quit(&quot;udp_connect error for %s, %s: %s&quot;,
host, serv, gai_strerror(n));
ressave = res;
do {
sockfd =
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0)
continue;/* ignore this one */
if (connect(sockfd, res->ai_addr, res->ai_addrlen) == 0)
break;/* success */
Close(sockfd);/* ignore this one */
} while ((res = res->ai_next) != NULL);
if (res == NULL)/* errno set from final connect() */
err_sys(&quot;udp_connect error for %s, %s&quot;, host, serv);
freeaddrinfo(ressave);
return (sockfd);
}
int Udp_connect(const char *host, const char *serv)
{
int n;
if ((n = udp_connect(host, serv)) < 0) {
err_quit(&quot;udp_connect error for %s, %s: %s&quot;,
host, serv, gai_strerror(-n));
}
return (n);
}
void Write(int fd, void *ptr, int nbytes)
{
if (write(fd, ptr, nbytes) != nbytes)
err_sys(&quot;write error&quot;);
}
ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
if ((n = read(fd, ptr, nbytes)) == -1)
err_sys(&quot;read error&quot;);
return (n);
}
int main(int argc, char **argv)
{
int sockfd, n;
char recvline;
if (argc != 3)
err_quit
(&quot;usage: daytimeudpcli2 <hostname/IPaddress> <service/port#>&quot;);
sockfd = Udp_connect(argv, argv);
Write(sockfd, (void *)&quot;&quot;, 1);/* send 1-byte datagram */
n = Read(sockfd, recvline, MAXLINE);
recvline = '\0';/* null terminate */
Fputs(recvline, stdout);
exit(0);
}

11.16 udp_server函数

11.16.1 协议无关的时间获取服务器程序

#define_POSIX_SOURCE
#include<strings.h>
#include<netinet/in.h>/* sockaddr_in{} and other Internet defns */
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<time.h>
#include<stdarg.h>/* ANSI C header file */
#include<netdb.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<sys/un.h>
#define IPV6
#defineMAXLINE4096/* max text line length */
#defineSAstruct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf;
errno_save = errno;/* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), &quot;: %s&quot;, strerror(errno_save));
strcat(buf, &quot;\n&quot;);
fflush(stdout);/* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);/* SunOS 4.1.* doesn't grok NULL argument */
return;
}
void err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, fmt, ap);
va_end(ap);
exit(1);
}
void err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, fmt, ap);
va_end(ap);
exit(1);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys(&quot;socket error&quot;);
return (n);
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
err_sys(&quot;bind error&quot;);
}
ssize_t Recvfrom(int fd, void *ptr, size_t nbytes, int flags,
struct sockaddr *sa, socklen_t * salenptr)
{
ssize_t n;
if ((n = recvfrom(fd, ptr, nbytes, flags, sa, salenptr)) < 0)
err_sys(&quot;recvfrom error&quot;);
return (n);
}
void Sendto(int fd, const void *ptr, size_t nbytes, int flags,
const struct sockaddr *sa, socklen_t salen)
{
if (sendto(fd, ptr, nbytes, flags, sa, salen) != (ssize_t) nbytes)
err_sys(&quot;sendto error&quot;);
}
void Close(int fd)
{
if (close(fd) == -1)
err_sys(&quot;close error&quot;);
}
int udp_server(const char *host, const char *serv, socklen_t * addrlenp)
{
int sockfd, n;
struct addrinfo hints, *res, *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)
err_quit(&quot;udp_server error for %s, %s: %s&quot;,
host, serv, gai_strerror(n));
ressave = res;
do {
sockfd =
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (sockfd < 0)
continue;/* error - try next one */
if (bind(sockfd, res->ai_addr, res->ai_addrlen) == 0)
break;/* success */
Close(sockfd);/* bind error - close and try next one */
} while ((res = res->ai_next) != NULL);
if (res == NULL)/* errno from final socket() or bind() */
err_sys(&quot;udp_server error for %s, %s&quot;, host, serv);
if (addrlenp)
*addrlenp = res->ai_addrlen;/* return size of protocol address */
freeaddrinfo(ressave);
return (sockfd);
}
/* end udp_server */
int Udp_server(const char *host, const char *serv, socklen_t * addrlenp)
{
return (udp_server(host, serv, addrlenp));
}
char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char portstr;
static char str;/* Unix domain is largest */
switch (sa->sa_family) {
case AF_INET:{
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
if (inet_ntop(AF_INET, &sin->sin_addr, str, sizeof(str))
== NULL)
return (NULL);
if (ntohs(sin->sin_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;:%d&quot;,
ntohs(sin->sin_port));
strcat(str, portstr);
}
return (str);
}
/* end sock_ntop */
#ifdefIPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
str = '[';
if (inet_ntop
(AF_INET6, &sin6->sin6_addr, str + 1,
sizeof(str) - 1) == NULL)
return (NULL);
if (ntohs(sin6->sin6_port) != 0) {
snprintf(portstr, sizeof(portstr), &quot;]:%d&quot;,
ntohs(sin6->sin6_port));
strcat(str, portstr);
return (str);
}
return (str + 1);
}
#endif
#ifdefAF_UNIX
case AF_UNIX:{
struct sockaddr_un *unp = (struct sockaddr_un *)sa;
/* OK to have no pathname bound to the socket: happens on
every connect() unless client calls bind() first. */
if (unp->sun_path == 0)
strcpy(str, &quot;(no pathname bound)&quot;);
else
snprintf(str, sizeof(str), &quot;%s&quot;, unp->sun_path);
return (str);
}
#endif
#ifdefHAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), &quot;%*s (index %d)&quot;,
sdl->sdl_nlen, &sdl->sdl_data,
sdl->sdl_index);
else
snprintf(str, sizeof(str), &quot;AF_LINK, index=%d&quot;,
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
&quot;sock_ntop: unknown AF_xxx: %d, len %d&quot;, sa->sa_family,
salen);
return (str);
}
return (NULL);
}
char *Sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char *ptr;
if ((ptr = sock_ntop(sa, salen)) == NULL)
err_sys(&quot;sock_ntop error&quot;);/* inet_ntop() sets errno */
return (ptr);
}
int main(int argc, char **argv)
{
int sockfd;
ssize_t n;
char buff;
time_t ticks;
socklen_t len;
struct sockaddr_storage cliaddr;
if (argc == 2)
sockfd = Udp_server(NULL, argv, NULL);
else if (argc == 3)
sockfd = Udp_server(argv, argv, NULL);
else
err_quit(&quot;usage: daytimeudpsrv [ <host> ] <service or port>&quot;);
for (;;) {
len = sizeof(cliaddr);
n = Recvfrom(sockfd, buff, MAXLINE, 0, (SA *) & cliaddr, &len);
printf(&quot;datagram from %s\n&quot;, Sock_ntop((SA *) & cliaddr, len));
ticks = time(NULL);
snprintf(buff, sizeof(buff), &quot;%.24s\r\n&quot;, ctime(&ticks));
Sendto(sockfd, buff, strlen(buff), 0, (SA *) & cliaddr, len);
}
}
页: [1]
查看完整版本: Unix网络编程代码 第11章 名字与地址转换