#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)
syslog(LOG_ERR, "addr is %s/n", buf);
if ((sockfd = initserver(aip->ai_socktype, aip->ai_addr,
aip->ai_addrlen, QLEN)) >= 0) {
serve(sockfd);
exit(0);
}
}
exit(-1);
}
再來講說客戶端:類似地也有兩種狀況:
1 以服務的方式鏈接服務器:若是用戶只知道服務器提供的服務,而不知道其端口號,就用這種方式,而且咱們也須要在/etc/services裏登記,不然也 會出現「Servname not supported for ai_socktype」這樣的錯誤,可是端口號沒必要於服務器端同樣,下面是代碼:
代碼:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#define BUFLEN 128
extern connect_retry(int sockfd, const struct sockaddr *addr, socklen_t alen);
int
print_uptime(int sockfd)
{
int n;
char buf[BUFLEN];
while ((n= recv(sockfd, buf, BUFLEN, 0)) > 0) {
if (write(STDOUT_FILENO, buf, n) != n)
return(-1);
}
if (n < 0)
return(-1);
if (n == 0)
printf("nothing received/n");
return(0);
}
int
main(int argc, char *argv[])
{
struct addrinfo *ailist, *aip;
struct addrinfo hint;
struct sockaddr_in *sinp;
int sockfd;
int err;
char seraddr[INET_ADDRSTRLEN];
short serport;
if (argc != 2) {
printf("usage: %s <hostname>/n", argv[0]);
exit(-1);
}
hint.ai_family = 0;
hint.ai_socktype = SOCK_STREAM;
hint.ai_flags = AI_CANONNAME;
hint.ai_protocol = 0;
hint.ai_addrlen = 0;
hint.ai_addr = NULL;
hint.ai_canonname = NULL;
hint.ai_next = NULL;
if ((
err = getaddrinfo(argv[1], "ruptime", &hint, &ailist)) != 0) {
printf("getaddrinfo error: %s/n", gai_strerror(err));
exit(-1);
}
printf("getaddrinfo ok/n");
for (aip = ailist; aip != NULL; aip = aip->ai_next) {
sinp = (struct sockaddr_in *)aip->ai_addr;
if (inet_ntop(sinp->sin_family, &sinp->sin_addr, seraddr, INET_ADDRSTRLEN) != NULL)
{
printf("server address is %s/n", seraddr);
}
serport = ntohs(sinp->sin_port);
printf("server port is %d/n", serport);
if ((sockfd = socket(aip->ai_family, SOCK_STREAM, 0)) < 0) {
printf("create socket failed: %s/n", strerror(errno));
exit(-1);
}printf("create socket ok/n");
if (connect_retry(sockfd, aip->ai_addr, aip->ai_addrlen) < 0) {
printf("can't connect to %s: %s/n", argv[1], strerror(errno));
exit(-1);
} else {
printf("connect ok/n");
if (print_uptime(sockfd) < 0) {
printf("print_uptime error: %s/n", strerror(errno));
exit(-1);
}
}
}
exit(0);
}
2 以端口號的方式鏈接服務器:這個就有一點須要注意,hint的ai_flags不要設爲AI_PASSIVE,由於返回的地址不是用來監聽綁定的,通常設爲AI_CANONNAME,代碼就不貼了,照這上面的改改就能夠了。
我自認爲不太會寫東西,而且因爲種種緣由,已經24小時沒睡了,腦殼有點暈,再加上水平有限,因此有錯誤的地方兄弟們請指出來,另外有看不太明白的地方就跟帖,最後謝謝版主給我這個精,你們互相學習。