服务端:
#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);
}