APUE习题16.4

服务端:

#include <pthread.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <netdb.h>
#include <errno.h>
#include <dirent.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <limits.h>
#include <sys/types.h>

#define DIRNAME "/proc"
#define	QUENUM	8
#define	MAXSIZE 16	

struct s_pronum {
	int		pronum;
	char	pronumbuf[MAXSIZE];
};


static pthread_key_t	get_pronum_key;
static pthread_once_t	once = PTHREAD_ONCE_INIT;

static void
free_alloc_space(void *ptr)
{
	free(ptr);
}

static void
get_pronum_key_once(void)
{
	pthread_key_create(&get_pronum_key, free_alloc_space);
}

static char * 
get_pronum(void) //get process number
{
	int		temp, count = 0;
	DIR		*dp;
	struct dirent	*dirp;
	struct s_pronum *ptr;
 
	pthread_once(&once, get_pronum_key_once);
	
	if ((ptr = pthread_getspecific(get_pronum_key)) == NULL) {
		if ((ptr = (struct s_pronum *)calloc(1, sizeof(struct s_pronum))) == NULL) {   //calloc is not signal safe
			fprintf(stderr, "no available memery\n");
			return(NULL);
		}
		pthread_setspecific(get_pronum_key, ptr);
	}
	ptr->pronum = 0;

	if ((dp = opendir(DIRNAME)) == NULL) {   //open "/proc" to get process number
		fprintf(stderr, "opendir failure: %s\n", strerror(errno));   //errno is not reenterable, it's static variable
		return(NULL);
	}

	while((dirp = readdir(dp)) != NULL) {  //get next struct dirent
		if (sscanf(dirp->d_name, "%d", &temp) > 0)   //if the file name is numeric ,there is a process
			ptr->pronum++;
	}
	printf("process number is %d now\n", ptr->pronum);
	snprintf(ptr->pronumbuf, MAXSIZE, "%d", ptr->pronum);

	return(ptr->pronumbuf);
}


static void *
send_pronum(void *data)
{
	int		err;
	int		connfd;
	char	*pronumbuf;

	connfd = *(int *)data;
	free(data); //free connfd memery

	for (; ;) {
		if ((pronumbuf = get_pronum()) == NULL) {
			fprintf(stderr, "get_pronum error\n");
			pthread_exit(NULL);
		}
		if (write(connfd , pronumbuf, strlen(pronumbuf) + 1) < 0) { //sizeof(pronumbuf) is wrong
			fprintf(stderr, "write error: %s\n", strerror(errno));
			pthread_exit(NULL);
		}
		printf("write done\n");

		sleep(2);
	}
}

int
main(int argc, char *argv[])
{
	int			listenfd, *connfdp;
	int			err;
	socklen_t	len;
	struct addrinfo 	hint, *res, *restemp;
	struct sockaddr_in	cliaddr;
	pthread_t	tid;
	char		clihost[MAXSIZE], cliport[MAXSIZE];
	pthread_attr_t		attr;
	
	if (argc != 2) {
		fprintf(stderr, "incorrect enter\n");
		exit(1);
	}

	if ((err = pthread_attr_init(&attr)) != 0) {
		fprintf(stderr, "pthread_attr_init error: %s\n", strerror(err));
		exit(1);
	}
	if ((err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED)) != 0) {//create detach pthread, also can use pthread_detach
		fprintf(stderr, "pthread_attr_setdetachstat error: %s\n", strerror(err));
		exit(1);
	}
	
	bzero(&hint, sizeof(hint));
	hint.ai_flags = AI_PASSIVE;
	hint.ai_family = AF_INET;
	hint.ai_socktype = SOCK_STREAM;
	hint.ai_protocol = 0;
	
	if ((err = getaddrinfo(NULL, argv[1], &hint, &res) != 0)) {
		fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(err));
		exit(1);
	}
	for (restemp = res; res != NULL; res = res->ai_next) {      //get listen socket
		if ((listenfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) 
			continue;
		if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
			break;
		close(listenfd);
	}

	if (res == NULL) {
		fprintf(stderr, "no available address\n");
		exit(1);
	}
	freeaddrinfo(restemp);

	if (listen(listenfd, QUENUM) != 0) {
		fprintf(stderr, "listen error: %s\n", strerror(errno));
		exit(1);
	}
	printf("start accept request!\n");

	for (; ;) {
		len = sizeof(cliaddr);
		if ((connfdp = malloc(sizeof(int))) == NULL) {  //just in case, make connfd to be private
			fprintf(stderr, "no available memery\n");
			exit(1);
		}

		if ((*connfdp = accept(listenfd, (struct sockaddr *)&cliaddr, &len)) < 0) { 
			fprintf(stderr, "accept error: %s", strerror(errno));
			continue;
		}

		if ((err = getnameinfo((struct sockaddr *)&cliaddr, sizeof(cliaddr), //get client host and port
								clihost, MAXSIZE, cliport,MAXSIZE, NI_NUMERICSERV)) != 0) {
			fprintf(stderr, "getnameinfo error: %s\n", gai_strerror(err));
			return(1);
		}

		if (pthread_create(&tid, &attr, send_pronum, connfdp) != 0) { //once get a connfd , create a pthread immediately
			fprintf(stderr, "pthread_create error\n");
			close(*connfdp);  //if failure, close connection and free the memery we requested
			free(connfdp);
		}
		printf("pthread %ld connect to client %s port %s\n", tid, clihost, cliport);
	}

	exit(0);
}

客户端:

#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <netdb.h>

#define MAXSIZE		20

int
main(int argc, char *argv[])
{
	struct addrinfo		hints, *res, *restemp;
	int		err, sockfd;
	char	buf[MAXSIZE];

	if (argc != 3) {
		fprintf(stderr, "incorrect enter\n");
		exit(1);
	}
	
	bzero(&hints, sizeof(hints));
	hints.ai_flags = 0;
	hints.ai_family = AF_INET;
	hints.ai_socktype = SOCK_STREAM;
	hints.ai_protocol = 0;
	if ((err = getaddrinfo(argv[1], argv[2], &hints, &res)) != 0)	{
		fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(err));
		exit(1);
	}

	for (restemp = res; restemp != NULL; restemp = restemp->ai_next) {
		if ((sockfd = socket(restemp->ai_family, restemp->ai_socktype, 
								restemp->ai_protocol)) < 0) {
			fprintf(stderr, "socket error: %s\n", strerror(errno));
			continue;
		}
		if (connect(sockfd, restemp->ai_addr, restemp->ai_addrlen) == 0) {
			printf("connect success\n");
			break;
		}
		close(sockfd);
	}

	if (restemp == NULL) {
		fprintf(stderr, "no available address\n");
		exit(1);
	}
	freeaddrinfo(res);

	while (read(sockfd, buf, MAXSIZE) != -1) {
		printf("process number on server is: %s\n", buf);
		sleep(2);
	}	
	
	exit(0);
}


你可能感兴趣的:(APUE习题16.4)