/************proto.h********************/
#ifndef __PROTO_H__
#define __PROTO_H__
#define FORMAT "%ld\n"
#define MINIDLEPROCNUM 5
#define MAXIDLEPROCNUM 10
#define MAXPROCNUM 20
#define SERVERPORT "4096"
#endif
/************server.c********************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <time.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include <signal.h>
#include <sys/mman.h>
#include "proto.h"
#define BUFFSIZE 64
#define IPSIZE 40
enum proc_state
{
IDLE_STATE = 0,
BUSY_STATE,
MAX_STATE
};
struct proc_st
{
int state;
pid_t pid;
};
static int idle_num =0;
static int busy_num =0;
static struct proc_st *procArray;
static int sockfd;
static void proc_work(int pos);
static int add_one_worker(void);
static int del_one_worker(void);
static int find_pos(void);
static void show_workProc(void);
static void usr2_handler(int num)
{
fprintf(stdout,"get signal\n");
}
int main()
{
struct sigaction sa, osa;
sigset_t set, oset;
struct sockaddr_in laddr;
int val =1;
int pos;
sa.sa_handler = SIG_IGN;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_NOCLDWAIT;
sigaction(SIGCHLD, &sa, &osa);
sa.sa_handler = usr2_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sigaction(SIGUSR2, &sa, &osa);
sigemptyset(&set);
sigaddset(&set, SIGUSR2);
if(sigprocmask(SIG_BLOCK, &set, &oset)<0)
{
perror("sigprocmask()");
exit(1);
}
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0)
{
perror("socket()");
exit(1);
}
if(setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &val , sizeof(val))<0)
{
perror("setsockopt()");
exit(1);
}
laddr.sin_family = AF_INET;
laddr.sin_port = htons(atoi(SERVERPORT));
inet_pton(AF_INET,"0.0.0.0",&laddr.sin_addr);
if(bind(sockfd, (void *)&laddr, sizeof(laddr))<0)
{
perror("bind()");
exit(1);
}
if(listen(sockfd, 100)<0)
{
perror("listen()");
exit(1);
}
procArray = mmap(NULL, sizeof(struct proc_st)*MAXPROCNUM, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if(procArray == MAP_FAILED)
{
perror("mmap()");
exit(1);
}
for(int i=0; i<MAXPROCNUM; i++)
{
procArray[i].state =-1;
}
for(int i=0;i<MINIDLEPROCNUM;i++)
{
pid_t pid;
pos = find_pos();
if(pos <0)
{
fprintf(stderr, "find pos failed\n");
exit(1);
}
//创建进程
pid = fork();
if(pid<0)
{
perror("fork()");
exit(1);
}
if(pid ==0)
{
proc_work(pos);
}
else
{
procArray[pos].state = IDLE_STATE;
procArray[pos].pid = pid;
idle_num ++;
}
}
while(1)
{
//等待SET集信号
sigsuspend(&oset);
if(idle_num <MINIDLEPROCNUM)
{
add_one_worker();
}
if(idle_num >MAXIDLEPROCNUM)
{
del_one_worker();
}
show_workProc();
}
sigprocmask(SIG_SETMASK, &oset, NULL);
close(sockfd);
exit(0);
}
//while true; do (./client &); sleep 1; done
static int add_one_worker(void)
{
pid_t pid;
int pos;
if((idle_num + busy_num)>= MAXPROCNUM)
return -1;
pos = find_pos();
if(pos <0)
{
fprintf(stderr, "find pos failed\n");
exit(1);
}
//创建进程
pid = fork();
if(pid<0)
{
perror("fork()");
exit(1);
}
if(pid ==0)
{
proc_work(pos);
}
else
{
procArray[pos].state = IDLE_STATE;
procArray[pos].pid = pid;
idle_num ++;
}
return 0;
}
static int del_one_worker(void)
{
int i;
for(i=0;i<MAXPROCNUM;i++)
{
if(procArray[i].state == IDLE_STATE)
{
kill(procArray[i].pid, SIGQUIT);
procArray[i].state = -1;
idle_num --;
return 0;
}
}
return 0;
}
static void show_workProc(void)
{
int idle_cal =0, busy_cal =0;
for(int i=0;i<MAXPROCNUM;i++)
{
if(procArray[i].state == -1)
{
//进程未创建
putchar(' ');
}
else if(procArray[i].state == IDLE_STATE)
{
//进程空闲
putchar('.');
idle_cal ++;
}
else if(procArray[i].state == BUSY_STATE)
{
//进程忙碌
putchar('x');
busy_cal ++;
}
}
putchar('\n');
idle_num =idle_cal;
busy_num =busy_cal;
}
static int find_pos(void)
{
int i;
for(i=0;i<MAXPROCNUM;i++)
{
if(procArray[i].state == -1)
return i;
}
return -1;
}
static void proc_work(int pos)
{
int clientfd;
struct sockaddr_in raddr;
socklen_t lenth =0;
time_t currentTime;
char buff[BUFFSIZE];
char ip[IPSIZE];
while(1)
{
clientfd = accept(sockfd, (void *)&raddr, &lenth);
if(clientfd<0)
{
perror("accept()");
continue;
}
//显示客户端信息
// inet_ntop(AF_INET, raddr.sin_addr, ip, IPSIZE);
// sprintf(stdout,"ip:%s port:%d\n",ip, ntohs(raddr.sin_port));
//切换进程状态
procArray[pos].state = BUSY_STATE;
kill(getppid(), SIGUSR2);
//发送时间戳
currentTime = time(NULL);
snprintf(buff, BUFFSIZE, FORMAT, currentTime);
send(clientfd, buff, BUFFSIZE, 0);
sleep(5);
close(clientfd);
//切换进程状态
procArray[pos].state = IDLE_STATE;
kill(getppid(), SIGUSR2);
}
exit(0);
}
/********************client.c********************/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <unistd.h>
#include <time.h>
#include <arpa/inet.h>
#include <sys/wait.h>
#include "proto.h"
#define BUFFSIZE 40
int main()
{
struct sockaddr_in raddr;
int val =1;
int sockfd;
char buff[BUFFSIZE] = {0};
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(sockfd<0)
{
perror("socket()");
exit(1);
}
raddr.sin_family = AF_INET;
raddr.sin_port = htons(atoi(SERVERPORT));
inet_pton(AF_INET,"0.0.0.0",&raddr.sin_addr);
if(connect(sockfd, (void *)&raddr, sizeof(raddr))<0)
{
perror("connect()");
exit(1);
}
recv(sockfd, buff, BUFFSIZE, 0);
fprintf(stdout, "%s", buff);
close(sockfd);
exit(0);
}