http://blog.csdn.net/andyxie407/article/details/1672325 关于怎样实现守护进程的。
函数原型:
- int getaddrinfo(const char *node, const char *service, const struct addrinfo *hints, struct addrinfo **res);
- void freeaddrinfo(struct addrinfo *res);
-
- struct addrinfo
- { int ai_flags;
- int ai_family;
- int ai_socktype;
- int ai_protocol;
- size_t ai_addrlen;
- struct sockaddr *ai_addr; /* 我觉得这个成员是这个函数最大的便利。 */
- char *ai_canonname;
- struct addrinfo *ai_next;
- };
-
参数: node 即 主机名称 ,可以是主机名称字符串,比如“hostname", 也可以是IP地址的字符串,比如“ 192.169.1.1”
service 服务 即端口号 可以是一个服务的名称,比如"http", 也可以是一个数字字符串 ,比如“80” .
hints 可以理解为约束条件,即你创建的,要获得的addrinfo结构,有什么约束。 在hints中进行设置
res 很明显,这个就是我们最终获得的addrinfo结构。
这个函数产生原因。 以前版本里面需要套接字编程,要得到sockaddr 类型: 必须使用两种函数 getserverbyname (一类的函数) 和 gethostent (一类的函数), 然后构建 sockaddr_in 结构,在强制类型转换得到 sockaddr结构。 但是 getaddrinfo有了这个函数,这里过程就不用了,直接调用,就能得到 sockaddr 。 简化了编程过程。
注意点是: 这个函数,说起来,是get ,但是其实可以理解为creat 或者是理解为构建 。 因为你可以随意构建自己的地址结构addrinfo。
下面解释一下 hints 参数。 为什么要有这个参数 ?
看一个小程序:
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <fcntl.h>
- #include <time.h>
- #include <ctype.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/wait.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/stat.h>
- #include <netdb.h>
- #include <sys/socket.h>
- void main()
- {
- struct addrinfo *ailist, *aip;
- struct addrinfo hint;
- struct sockaddr_in *sinp;
- char *hostname = "luoyedeshan"; /* 这是我的用户名 */
- char buf[INET_ADDRSTRLEN];
- char *server = "3294"; /* 这是服务端口号 */
- const char *addr;
- int ilRc;
- hint.ai_family = AF_UNSPEC; /* hint 的限定设置 */
- hint.ai_socktype = 0; /* 这里可是设置 socket type . 比如 SOCK——DGRAM */
- hint.ai_flags = AI_PASSIVE; /* flags 的标志很多 。常用的有AI_CANONNAME; */
- hint.ai_protocol = 0; /* 设置协议 一般为0,默认 */
- hint.ai_addrlen = 0; /* 下面不可以设置,为0,或者为NULL */
- hint.ai_canonname = NULL;
- hint.ai_addr = NULL;
- hint.ai_next = NULL;
- ilRc = getaddrinfo(hostname, server, &hint, &ailist);
- if (ilRc < 0)
- {
- char str_error[100];
- strcpy(str_error,gai_strerror(errno));
- printf("str_error = %s", str_error);
- return;
- }
-
- for (aip = ailist; aip != NULL; aip = aip->ai_next) /* 显示获取的信息 */
- {
- sinp = (struct sockaddr_in *)aip->ai_addr; /* 为什么是for 循环 ,先向下看 */
- addr = inet_ntop(AF_INET, &sinp->sin_addr, buf, INET_ADDRSTRLEN);
- printf(" addr = %s", addr?addr:"unknow ");
- printf("port = %d ", ntohs(sinp->sin_port));
- printf(" \n");
- }
- }
/* 执行结果如下 */
[luoyedeshan@luoyedeshan wqr]$ ./a.out
addr = 0.0.0.0 port = 3294
addr = 0.0.0.0 port = 3294
addr = 0.0.0.0 port = 3294
addr = 192.168.1.100 port = 3294
addr = 192.168.1.100 port = 3294
addr = 192.168.1.100 port = 3294
细心的你,也许发现,为什么重复了3次, 0.0.0.0 是本地地址,没话说, 192.168.1.100是局域网地址, 也没什么,为什么会得到3个重复的呢??
这就是 hint的作用,源代码里面我没甚至什么,hint都为空,所有有3个。 你在hint设置了,就可以屏蔽掉一些对你没用的addrinfo结构. 虽然有三个,他们的IP地址和端口号都一样,但是 这三个套接字类型不一样。 我试过 ,分别为 下面三种套接字类型 SOCK_DGRAM SOCK_SEQPACKET SOCK_STREAM .
1,服务器端以服务的形式提供给用户,下面的代码是用到的库函数
- #include <sys/socket.h>
- #include <sys/resource.h>
- #include <sys/stat.h>
- #include <errno.h>
- #include <unistd.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include <fcntl.h>
- #include <syslog.h>
-
- #define MAXSLEEP 128
-
- int
- connect_retry(int sockfd, const struct sockaddr *addr, socklen_t alen)
- {
- int nsec;
-
- for (nsec = 1; nsec <= MAXSLEEP; nsec <<= 1) {
- if (connect(sockfd, addr, alen) == 0)
- return(0);
- if (nsec <= MAXSLEEP/2)
- sleep(nsec);
- }
- return(-1);
- }
-
- int
- initserver(int type, const struct sockaddr *addr, socklen_t alen, int qlen)
- {
- int fd;
- int err = 0;
- int reuse = 1;
-
- if ((fd = socket(addr->sa_family, type, 0)) < 0)
- return(-1);
- if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(int)) < 0) {
- err = errno;
- goto errout;
- }
- if (bind(fd, addr, alen) < 0) {
- err = errno;
- goto errout;
- }
- if ((type == SOCK_STREAM) || (type == SOCK_SEQPACKET)) {
- if (listen(fd, qlen) < 0) {
- err = errno;
- goto errout;
- }
- }
- return(fd);
- errout:
- close(fd);
- errno = err;
- return(-1);
- }
-
- void
- daemonize(const char *cmd)
- {
- int i, fd0, fd1, fd2;
- pid_t pid;
- struct rlimit rl;
- struct sigaction sa;
-
- umask(0);
-
- if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
- printf("getrlimit failed");
- exit(1);
- }
-
- if ((pid = fork()) < 0) {
- printf("first fork failed");
- exit(1);
- } else if (pid > 0) {
- exit(0);
- }
-
- setsid();
-
- sa.sa_handler = SIG_IGN;
- sigemptyset(&sa.sa_mask);
- sa.sa_flags = 0;
- if (sigaction(SIGHUP, &sa, NULL) < 0) {
- printf("sigaction failed");
- exit(1);
- }
- if ((pid = fork()) < 0) {
- printf("second fork failed");
- exit(1);
- } else if (pid > 0) {
- exit(0);
- }
-
- if (chdir("/") < 0) {
- printf("chdir failed");
- exit(1);
- }
-
- if (rl.rlim_max == RLIM_INFINITY)
- rl.rlim_max = 1024;
- for (i = 0; i < rl.rlim_max; i )
- close(i);
-
- fd0 = open("/dev/null", O_RDWR);
- fd1 = dup(0);
- fd2 = dup(0);
-
- openlog(cmd, LOG_CONS, LOG_DAEMON);
- if (fd0 != 0 || fd1 != 1 || fd2 != 2) {
- syslog(LOG_ERR, "unexpected file descriptor %d %d %d", fd0, fd1, fd2);
- exit(1);
- }
- }
192.168.1.104 wawxdyy
# The following lines are desirable for IPv6 capable hosts
::1 ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
ff02::3 ip6-allhosts
如果要想以服务的形式运行服务器程序,这两个参数一定要明确指定,并且主机名不能是localhost,只有这样返回的结果才是有效的,才能用于后面的绑定。
2 服务器程序用端口号的形式发布: 这种情况下就没有必要在/etc/services里登记了,但是hint结构的ai_flags的参数设定有注意的地方,在上面的那种情况,因为主机名 和服务名都明确提供了,所以即使ai_flags设为0也能返回正确的结果,但是现在我们将第二个参数设为端口号,这样的话,我们必须将hint结构的 ai_flags设为AI_PASSIVE,这样返回的结果才能用于后面的监听绑定,否则不能, 因为AI_PASSIVE就是告诉getaddrinfo返回的地址是用于监听绑定的。下面是相关的代码:
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <unistd.h>
- #include <syslog.h>
- #include <netdb.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <sys/wait.h>
- #include <fcntl.h>
-
- #ifndef HOST_NAME_MAX
- #define HOST_NAME_MAX 64
- #endif
-
- #define BUFLEN 128
- #define QLEN 10
-
- extern int initserver(int, const struct sockaddr *, socklen_t, int);
- extern void daemonize(const char *);
-
- void
- serve(int sockfd)
- {
- int clfd, status;
- pid_t pid;
-
- for (;;) {
- if ((clfd = accept(sockfd, NULL, NULL)) < 0) {
- syslog(LOG_ERR, "accept error: %m\n");
- exit(-1);
- }
-
- if ((pid = fork()) < 0) {
- syslog(LOG_ERR, "fork error: %m\n");
- exit(-1);
- } else if (pid == 0) {
- if (dup2(clfd, STDOUT_FILENO) != STDOUT_FILENO ||
- dup2(clfd, STDERR_FILENO) != STDERR_FILENO) {
- syslog(LOG_ERR, "dup2 error: %m\n");
- exit(-1);
- }
- close(clfd);
- execl("/usr/bin/uptime", "uptime", (char *)0);
- syslog(LOG_ERR, "unexpected return from execl: %m");
- } else {
- close(clfd);
- waitpid(pid, &status, 0);
- }
- }
- }
-
- int
- main(void)
- {
- struct addrinfo *ailist, *aip;
- struct addrinfo hint;
- struct sockaddr_in *sinp;
- int sockfd;
- int err, n;
- char *host;
- char buf[INET_ADDRSTRLEN];
-
- #ifdef _SC_HOST_NAME_MAX
- n = sysconf(_SC_HOST_NAME_MAX);
- if (n < 0)
- #endif
- n = HOST_NAME_MAX;
-
- if ((host = malloc(n)) == NULL) {
- printf("malloc error: %s\n", strerror(errno));
- exit(-1);
- }
- if (gethostname(host, n) < 0) {
- printf("gethostname error: %s\n", strerror(errno));
- exit(-1);
- }
- syslog(LOG_ERR, "hostname is %s", host);
- daemonize("ruptimed");
-
- hint.ai_flags = AI_PASSIVE;
- hint.ai_family = 0;
- hint.ai_socktype = SOCK_STREAM;
- hint.ai_protocol = 0;
- hint.ai_addrlen = 0;
- hint.ai_addr = NULL;
- hint.ai_canonname = NULL;
- hint.ai_next = NULL;
- if ((err = getaddrinfo(NULL, "2000", &hint, &ailist)) != 0) {
- syslog(LOG_ERR, "getaddrinfo error: %s", gai_strerror(err));
- exit(-1);
- }
- for (aip = ailist; aip != NULL; aip = aip->ai_next) {
- sinp = (struct sockaddr_in *)aip->ai_addr;
- short port = ntohs(sinp->sin_port);
- syslog(LOG_ERR, "port is %d\n", port);
- if (inet_ntop(aip->ai_family, &sinp->sin_addr, buf, INET_ADDRSTRLEN) != NULL)
- 注:暂存的内容只能恢复到当前文章的编辑器中,如需恢复到其他文章中,请编辑该文章并从暂存箱中恢复;或者直接复制以上内容,手工恢复到相关文章。
- 恢复到编辑器 关闭