运行: ./server localhost daytime
查看日志: tail /var/log/syslog
#define _POSIX_SOURCE #include <time.h> #include <strings.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> #include <syslog.h> #include <signal.h> #include <fcntl.h> /* for nonblocking */ typedef void Sigfunc(int); /* for signal handlers */ #define MAXFD 64 #define MAXLINE 4096 /* max text line length */ #define LISTENQ 1024 /* 2nd argument to listen() */ #define SA struct sockaddr #define IPV6 int daemon_proc; /* set nonzero by daemon_init() */ void err_doit(int errnoflag, int level, const char *fmt, va_list ap) { int errno_save, n; char buf[MAXLINE + 1]; errno_save = errno; /* value caller might want printed */ #ifdef HAVE_VSNPRINTF vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ #else vsprintf(buf, fmt, ap); /* not safe */ #endif n = strlen(buf); if (errnoflag) snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); strcat(buf, "\n"); if (daemon_proc) { syslog(level, "%s", buf); } else { fflush(stdout); /* in case stdout and stderr are the same */ fputs(buf, stderr); fflush(stderr); } return; } void err_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, LOG_INFO, fmt, ap); va_end(ap); return; } void err_quit(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, LOG_ERR, fmt, ap); va_end(ap); exit(1); } void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_ERR, 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 Close(int fd) { if (close(fd) == -1) err_sys("close 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); } void Bind(int fd, const struct sockaddr *sa, socklen_t salen) { if (bind(fd, sa, salen) < 0) err_sys("bind error"); } void Write(int fd, void *ptr, int nbytes) { if (write(fd, ptr, nbytes) != nbytes) err_sys("write error"); } 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"); } 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("tcp_listen error for %s, %s: %s", 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("tcp_listen error for %s, %s", 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[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); } 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); } pid_t Fork(void) { pid_t pid; if ((pid = fork()) == -1) err_sys("fork error"); return (pid); } int daemon_init(const char *pname, int facility) { int i; pid_t pid; if ((pid = Fork()) < 0) return (-1); else if (pid) _exit(0); /* parent terminates */ /* child 1 continues... */ if (setsid() < 0) /* become session leader */ return (-1); Signal(SIGHUP, SIG_IGN); if ((pid = Fork()) < 0) return (-1); else if (pid) _exit(0); /* child 1 terminates */ /* child 2 continues... */ daemon_proc = 1; /* for err_XXX() functions */ chdir("/"); /* change working directory */ /* close off file descriptors */ for (i = 0; i < MAXFD; i++) close(i); /* redirect stdin, stdout, and stderr to /dev/null */ open("/dev/null", O_RDONLY); open("/dev/null", O_RDWR); open("/dev/null", O_RDWR); openlog(pname, LOG_PID, facility); return (0); /* success */ } void *Malloc(size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) err_sys("malloc error"); return (ptr); } int main(int argc, char **argv) { int listenfd, connfd; socklen_t addrlen, len; struct sockaddr *cliaddr; char buff[MAXLINE]; time_t ticks; if (argc < 2 || argc > 3) err_quit("usage: daytimetcpsrv2 [ <host> ] <service or port>"); daemon_init(argv[0], 0); if (argc == 2) listenfd = Tcp_listen(NULL, argv[1], &addrlen); else listenfd = Tcp_listen(argv[1], argv[2], &addrlen); cliaddr = (struct sockaddr *)Malloc(addrlen); for (;;) { len = addrlen; connfd = Accept(listenfd, cliaddr, &len); err_msg("connection from %s", Sock_ntop(cliaddr, len)); ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); Write(connfd, buff, strlen(buff)); Close(connfd); } }
要运行这个例子程序,
1.先要添加服务:做法,在/etc/services最后加上: mydaytime 9999/tcp
2.安装xinetd: sudo apt-get install xinetd
3.编辑配置:在/etc/xinetd.d/目录下新建一个mydaytime文件,内容如下:
service mydaytime
{
socket_type = stream
protocol = tcp
wait = no
user =root
server =/home/xpmo/unp/server
}
其中server是例子程序的路径
4.重启xinetdsudo killall -HUP xinetd
5.查看启动成功否:
sudo netstat -tlp
如果看到mydaytime就说明启动成功了。
例子代码:
#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 <arpa/inet.h> #include <sys/un.h> #include <syslog.h> #define MAXLINE 4096 /* max text line length */ #define IPV6 int daemon_proc; /* set nonzero by daemon_init() */ void err_doit(int errnoflag, int level, const char *fmt, va_list ap) { int errno_save, n; char buf[MAXLINE + 1]; errno_save = errno; /* value caller might want printed */ #ifdef HAVE_VSNPRINTF vsnprintf(buf, MAXLINE, fmt, ap); /* safe */ #else vsprintf(buf, fmt, ap); /* not safe */ #endif n = strlen(buf); if (errnoflag) snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save)); strcat(buf, "\n"); if (daemon_proc) { syslog(level, "%s", buf); } else { fflush(stdout); /* in case stdout and stderr are the same */ fputs(buf, stderr); fflush(stderr); } return; } void err_msg(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(0, LOG_INFO, fmt, ap); va_end(ap); return; } void err_sys(const char *fmt, ...) { va_list ap; va_start(ap, fmt); err_doit(1, LOG_ERR, fmt, ap); va_end(ap); exit(1); } void Close(int fd) { if (close(fd) == -1) err_sys("close error"); } void Write(int fd, void *ptr, int nbytes) { if (write(fd, ptr, nbytes) != nbytes) err_sys("write error"); } 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"); } 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 *Malloc(size_t size) { void *ptr; if ((ptr = malloc(size)) == NULL) err_sys("malloc error"); return (ptr); } void daemon_inetd(const char *pname, int facility) { daemon_proc = 1; /* for our err_XXX() functions */ openlog(pname, LOG_PID, facility); } void Getpeername(int fd, struct sockaddr *sa, socklen_t * salenptr) { if (getpeername(fd, sa, salenptr) < 0) err_sys("getpeername error"); } int main(int argc, char **argv) { socklen_t len; struct sockaddr *cliaddr; char buff[MAXLINE]; time_t ticks; daemon_inetd(argv[0], 0); cliaddr = (struct sockaddr *)Malloc(sizeof(struct sockaddr_storage)); len = sizeof(struct sockaddr_storage); Getpeername(0, cliaddr, &len); err_msg("connection from %s", Sock_ntop(cliaddr, len)); ticks = time(NULL); snprintf(buff, sizeof(buff), "%.24s\r\n", ctime(&ticks)); Write(0, buff, strlen(buff)); Close(0); /* close TCP connection */ exit(0); }