第8章 基本UDP套接字编程
8.3 UDP回射服务器程序
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h> /* ANSI C header file */
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys("socket error");
return (n);
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
err_sys("bind error");
}
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("recvfrom error");
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("sendto error");
}
void dg_echo(int sockfd, SA * pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
for (;;) {
len = clilen;
n = Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
Sendto(sockfd, mesg, n, 0, pcliaddr, len);
}
}
int main()
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(sockfd, (SA *) & servaddr, sizeof(servaddr));
dg_echo(sockfd, (SA *) & cliaddr, sizeof(cliaddr));
}
8.5 UDP回射客户程序
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton error for %s", strptr); /* errno set */
else if (n == 0)
err_quit("inet_pton error for %s", strptr); /* errno not set */
/* nothing to return */
}
char *Fgets(char *ptr, int n, FILE * stream)
{
char *rptr;
if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
err_sys("fgets error");
return (rptr);
}
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("recvfrom error");
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("sendto error");
}
void Fputs(const char *ptr, FILE * stream)
{
if (fputs(ptr, stream) == EOF)
err_sys("fputs error");
}
void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr,
servlen);
n = Recvfrom(sockfd, recvline, MAXLINE, 0, NULL, NULL);
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: udpcli <IPaddress>");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));
exit(0);
}
8.8 验证接收到的响应
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <sys/un.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton error for %s", strptr); /* errno set */
else if (n == 0)
err_quit("inet_pton error for %s", strptr); /* errno not set */
/* nothing to return */
}
char *Fgets(char *ptr, int n, FILE * stream)
{
char *rptr;
if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
err_sys("fgets error");
return (rptr);
}
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("recvfrom error");
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("sendto error");
}
void Fputs(const char *ptr, FILE * stream)
{
if (fputs(ptr, stream) == EOF)
err_sys("fputs error");
}
void *Malloc(size_t size)
{
void *ptr;
if ((ptr = malloc(size)) == NULL)
err_sys("malloc error");
return (ptr);
}
char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char portstr[8];
static char str[128]; /* 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), ":%d",
ntohs(sin->sin_port));
strcat(str, portstr);
}
return (str);
}
/* end sock_ntop */
#ifdef IPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
str[0] = '[';
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), "]:%d",
ntohs(sin6->sin6_port));
strcat(str, portstr);
return (str);
}
return (str + 1);
}
#endif
#ifdef AF_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] == 0)
strcpy(str, "(no pathname bound)");
else
snprintf(str, sizeof(str), "%s", unp->sun_path);
return (str);
}
#endif
#ifdef HAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), "%*s (index %d)",
sdl->sdl_nlen, &sdl->sdl_data[0],
sdl->sdl_index);
else
snprintf(str, sizeof(str), "AF_LINK, index=%d",
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
"sock_ntop: unknown AF_xxx: %d, len %d", 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("sock_ntop error"); /* inet_ntop() sets errno */
return (ptr);
}
void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
socklen_t len;
struct sockaddr *preply_addr;
preply_addr = (struct sockaddr *)Malloc(servlen);
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Sendto(sockfd, sendline, strlen(sendline), 0, pservaddr,
servlen);
len = servlen;
n = Recvfrom(sockfd, recvline, MAXLINE, 0, preply_addr, &len);
if (len != servlen || memcmp(pservaddr, preply_addr, len) != 0) {
printf("reply from %s (ignored)\n",
Sock_ntop(preply_addr, len));
continue;
}
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: udpcli <IPaddress>");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));
exit(0);
}
8.12 dg_cli函数(修订版)
//调用connect版本
//运行结果跟书上不符:向一个不可达的主机发起连接,没有返回连接拒绝的错误,read永远阻塞
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton error for %s", strptr); /* errno set */
else if (n == 0)
err_quit("inet_pton error for %s", strptr); /* errno not set */
/* nothing to return */
}
char *Fgets(char *ptr, int n, FILE * stream)
{
char *rptr;
if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
err_sys("fgets error");
return (rptr);
}
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("recvfrom error");
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("sendto error");
}
void Fputs(const char *ptr, FILE * stream)
{
if (fputs(ptr, stream) == EOF)
err_sys("fputs error");
}
void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (connect(fd, sa, salen) < 0)
err_sys("connect error");
}
void Write(int fd, void *ptr, int nbytes)
{
if (write(fd, ptr, nbytes) != nbytes)
err_sys("write error");
}
ssize_t Read(int fd, void *ptr, size_t nbytes)
{
ssize_t n;
if ((n = read(fd, ptr, nbytes)) == -1)
err_sys("read error");
return (n);
}
void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen)
{
int n;
char sendline[MAXLINE], recvline[MAXLINE + 1];
Connect(sockfd, (SA *) pservaddr, servlen);
while (Fgets(sendline, MAXLINE, fp) != NULL) {
Write(sockfd, sendline, strlen(sendline));
n = Read(sockfd, recvline, MAXLINE);
recvline[n] = 0; /* null terminate */
Fputs(recvline, stdout);
}
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: udpcli <IPaddress>");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));
exit(0);
}
8.13 UDP缺乏流量控制
8.13.1 写固定数目的数据报的客户端
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton error for %s", strptr); /* errno set */
else if (n == 0)
err_quit("inet_pton error for %s", strptr); /* errno not set */
/* nothing to return */
}
char *Fgets(char *ptr, int n, FILE * stream)
{
char *rptr;
if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
err_sys("fgets error");
return (rptr);
}
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("recvfrom error");
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("sendto error");
}
#define NDG 2000 /* datagrams to send */
#define DGLEN 1400 /* length of each datagram */
void dg_cli(FILE * fp, int sockfd, const SA * pservaddr, socklen_t servlen)
{
int i;
char sendline[DGLEN];
for (i = 0; i < NDG; i++) {
Sendto(sockfd, sendline, DGLEN, 0, pservaddr, servlen);
}
}
int main(int argc, char **argv)
{
int sockfd;
struct sockaddr_in servaddr;
if (argc != 2)
err_quit("usage: udpcli <IPaddress>");
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
dg_cli(stdin, sockfd, (SA *) & servaddr, sizeof(servaddr));
exit(0);
}
8.13.2 对接收数目进行计数的服务器端
#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 <stdarg.h> /* ANSI C header file */
#include <signal.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
typedef void Sigfunc(int); /* for signal handlers */
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys("socket error");
return (n);
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
err_sys("bind error");
}
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("recvfrom error");
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("sendto error");
}
static int count;
void recvfrom_int(int signo)
{
printf("\nreceived %d datagrams\n", count);
exit(0);
}
Sigfunc *signal(int signo, Sigfunc * func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
#endif
} else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
Sigfunc *Signal(int signo, Sigfunc * func)
{ /* for our signal() function */
Sigfunc *sigfunc;
if ((sigfunc = signal(signo, func)) == SIG_ERR)
err_sys("signal error");
return (sigfunc);
}
void dg_echo(int sockfd, SA * pcliaddr, socklen_t clilen)
{
socklen_t len;
char mesg[MAXLINE];
Signal(SIGINT, recvfrom_int);
for (;;) {
len = clilen;
Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
count++;
}
}
int main()
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(sockfd, (SA *) & servaddr, sizeof(servaddr));
dg_echo(sockfd, (SA *) & cliaddr, sizeof(cliaddr));
}
8.13.3 增大套接字接收队列大小
#define _POSIX_SOURCE
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h> /* ANSI C header file */
#include <signal.h>
#include <strings.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
typedef void Sigfunc(int); /* for signal handlers */
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys("socket error");
return (n);
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
err_sys("bind error");
}
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("recvfrom error");
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("sendto error");
}
static int count;
void recvfrom_int(int signo)
{
printf("\nreceived %d datagrams\n", count);
exit(0);
}
Sigfunc *signal(int signo, Sigfunc * func)
{
struct sigaction act, oact;
act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT; /* SunOS 4.x */
#endif
} else {
#ifdef SA_RESTART
act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}
Sigfunc *Signal(int signo, Sigfunc * func)
{ /* for our signal() function */
Sigfunc *sigfunc;
if ((sigfunc = signal(signo, func)) == SIG_ERR)
err_sys("signal error");
return (sigfunc);
}
void Setsockopt(int fd, int level, int optname, const void *optval,
socklen_t optlen)
{
if (setsockopt(fd, level, optname, optval, optlen) < 0)
err_sys("setsockopt error");
}
void dg_echo(int sockfd, SA * pcliaddr, socklen_t clilen)
{
int n;
socklen_t len;
char mesg[MAXLINE];
Signal(SIGINT, recvfrom_int);
n = 220 * 1024;
Setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, &n, sizeof(n));
for (;;) {
len = clilen;
Recvfrom(sockfd, mesg, MAXLINE, 0, pcliaddr, &len);
count++;
}
}
int main()
{
int sockfd;
struct sockaddr_in servaddr, cliaddr;
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(sockfd, (SA *) & servaddr, sizeof(servaddr));
dg_echo(sockfd, (SA *) & cliaddr, sizeof(cliaddr));
}
8.14 UDP中的外出接口的确定
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/un.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define SA struct sockaddr
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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("socket error");
return (n);
}
void Inet_pton(int family, const char *strptr, void *addrptr)
{
int n;
if ((n = inet_pton(family, strptr, addrptr)) < 0)
err_sys("inet_pton error for %s", strptr); /* errno set */
else if (n == 0)
err_quit("inet_pton error for %s", strptr); /* errno not set */
/* nothing to return */
}
char *Fgets(char *ptr, int n, FILE * stream)
{
char *rptr;
if ((rptr = fgets(ptr, n, stream)) == NULL && ferror(stream))
err_sys("fgets error");
return (rptr);
}
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("recvfrom error");
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("sendto error");
}
void Connect(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (connect(fd, sa, salen) < 0)
err_sys("connect error");
}
void Getsockname(int fd, struct sockaddr *sa, socklen_t * salenptr)
{
if (getsockname(fd, sa, salenptr) < 0)
err_sys("getsockname error");
}
char *sock_ntop(const struct sockaddr *sa, socklen_t salen)
{
char portstr[8];
static char str[128]; /* 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), ":%d",
ntohs(sin->sin_port));
strcat(str, portstr);
}
return (str);
}
/* end sock_ntop */
#ifdef IPV6
case AF_INET6:{
struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
str[0] = '[';
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), "]:%d",
ntohs(sin6->sin6_port));
strcat(str, portstr);
return (str);
}
return (str + 1);
}
#endif
#ifdef AF_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] == 0)
strcpy(str, "(no pathname bound)");
else
snprintf(str, sizeof(str), "%s", unp->sun_path);
return (str);
}
#endif
#ifdef HAVE_SOCKADDR_DL_STRUCT
case AF_LINK:{
struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;
if (sdl->sdl_nlen > 0)
snprintf(str, sizeof(str), "%*s (index %d)",
sdl->sdl_nlen, &sdl->sdl_data[0],
sdl->sdl_index);
else
snprintf(str, sizeof(str), "AF_LINK, index=%d",
sdl->sdl_index);
return (str);
}
#endif
default:
snprintf(str, sizeof(str),
"sock_ntop: unknown AF_xxx: %d, len %d", 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("sock_ntop error"); /* inet_ntop() sets errno */
return (ptr);
}
int main(int argc, char **argv)
{
int sockfd;
socklen_t len;
struct sockaddr_in cliaddr, servaddr;
if (argc != 2)
err_quit("usage: udpcli <IPaddress>");
sockfd = Socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_port = htons(SERV_PORT);
Inet_pton(AF_INET, argv[1], &servaddr.sin_addr);
Connect(sockfd, (SA *) & servaddr, sizeof(servaddr));
len = sizeof(cliaddr);
Getsockname(sockfd, (SA *) & cliaddr, &len);
printf("local address %s\n", Sock_ntop((SA *) & cliaddr, len));
exit(0);
}
8.15 使用select函数的TCP和UDP回射服务器程序
#include <netinet/in.h> /* sockaddr_in{} and other Internet defns */
#include <strings.h>
#include <sys/select.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <stdarg.h> /* ANSI C header file */
#include <signal.h>
#include <unistd.h>
#include <sys/wait.h>
#define MAXLINE 4096 /* max text line length */
#define SERV_PORT 9877 /* TCP and UDP */
#define LISTENQ 1024 /* 2nd argument to listen() */
#define max(a,b) ((a) > (b) ? (a) : (b))
#define SA struct sockaddr
typedef void Sigfunc(int); /* for signal handlers */
void err_doit(int errnoflag, const char *fmt, va_list ap)
{
int errno_save;
char buf[MAXLINE];
errno_save = errno; /* value caller might want printed */
vsprintf(buf, fmt, ap);
if (errnoflag)
sprintf(buf + strlen(buf), ": %s", strerror(errno_save));
strcat(buf, "\n");
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);
}
int Socket(int family, int type, int protocol)
{
int n;
if ((n = socket(family, type, protocol)) < 0)
err_sys("socket error");
return (n);
}
void Bind(int fd, const struct sockaddr *sa, socklen_t salen)
{
if (bind(fd, sa, salen) < 0)
err_sys("bind error");
}
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("recvfrom error");
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("sendto error");
}
Sigfunc *Signal(int signo, Sigfunc * func)
{ /* for our signal() function */
Sigfunc *sigfunc;
if ((sigfunc = signal(signo, func)) == SIG_ERR)
err_sys("signal error");
return (sigfunc);
}
void Setsockopt(int fd, int level, int optname, const void *optval,
socklen_t optlen)
{
if (setsockopt(fd, level, optname, optval, optlen) < 0)
err_sys("setsockopt error");
}
void Listen(int fd, int backlog)
{
char *ptr;
/*4can override 2nd argument with environment variable */
if ((ptr = getenv("LISTENQ")) != NULL)
backlog = atoi(ptr);
if (listen(fd, backlog) < 0)
err_sys("listen error");
}
int Accept(int fd, struct sockaddr *sa, socklen_t * salenptr)
{
int n;
again:
if ((n = accept(fd, sa, salenptr)) < 0) {
#ifdef EPROTO
if (errno == EPROTO || errno == ECONNABORTED)
#else
if (errno == ECONNABORTED)
#endif
goto again;
else
err_sys("accept error");
}
return (n);
}
pid_t Fork(void)
{
pid_t pid;
if ((pid = fork()) == -1)
err_sys("fork error");
return (pid);
}
void Close(int fd)
{
if (close(fd) == -1)
err_sys("close error");
}
ssize_t writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;
ptr = (const char *)vptr;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0; /* and call write() again */
else
return (-1); /* error */
}
nleft -= nwritten;
ptr += nwritten;
}
return (n);
}
void Writen(int fd, void *ptr, int nbytes)
{
if (writen(fd, ptr, nbytes) != nbytes)
err_sys("writen error");
}
void str_echo(int sockfd)
{
ssize_t n;
char buf[MAXLINE];
again:
while ((n = read(sockfd, buf, MAXLINE)) > 0)
Writen(sockfd, buf, n);
if (n < 0 && errno == EINTR)
goto again;
else if (n < 0)
err_sys("str_echo: read error");
}
void sig_chld(int signo)
{
pid_t pid;
int stat;
while ((pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
}
int main()
{
int listenfd, connfd, udpfd, nready, maxfdp1;
char mesg[MAXLINE];
pid_t childpid;
fd_set rset;
ssize_t n;
socklen_t len;
const int on = 1;
struct sockaddr_in cliaddr, servaddr;
/* 4create listening TCP socket */
listenfd = Socket(AF_INET, SOCK_STREAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
Bind(listenfd, (SA *) & servaddr, sizeof(servaddr));
Listen(listenfd, LISTENQ);
/* 4create UDP socket */
udpfd = Socket(AF_INET, SOCK_DGRAM, 0);
bzero(&servaddr, sizeof(servaddr));
servaddr.sin_family = AF_INET;
servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
servaddr.sin_port = htons(SERV_PORT);
Bind(udpfd, (SA *) & servaddr, sizeof(servaddr));
/* end udpservselect01 */
/* include udpservselect02 */
Signal(SIGCHLD, sig_chld); /* must call waitpid() */
FD_ZERO(&rset);
maxfdp1 = max(listenfd, udpfd) + 1;
for (;;) {
FD_SET(listenfd, &rset);
FD_SET(udpfd, &rset);
if ((nready = select(maxfdp1, &rset, NULL, NULL, NULL)) < 0) {
if (errno == EINTR)
continue; /* back to for() */
else
err_sys("select error");
}
if (FD_ISSET(listenfd, &rset)) {
len = sizeof(cliaddr);
connfd = Accept(listenfd, (SA *) & cliaddr, &len);
if ((childpid = Fork()) == 0) { /* child process */
Close(listenfd); /* close listening socket */
str_echo(connfd); /* process the request */
exit(0);
}
Close(connfd); /* parent closes connected socket */
}
if (FD_ISSET(udpfd, &rset)) {
len = sizeof(cliaddr);
n = Recvfrom(udpfd, mesg, MAXLINE, 0, (SA *) & cliaddr,
&len);
Sendto(udpfd, mesg, n, 0, (SA *) & cliaddr, len);
}
}
}