工作流程图
头文件声明
prool.h
#include <stdio.h>
#include<sys/sendfile.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <time.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <netinet/in.h>
#include <netdb.h>
#include <sys/mman.h>
#include <sys/select.h>
#include <sys/time.h>
#include <pthread.h>
#include <setjmp.h>
#include <sys/time.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/msg.h>
#include <sys/uio.h>
#include <arpa/inet.h>
#include <sys/shm.h>
#include <sys/epoll.h>
#define ARGS_CHECK(argc, val) \
if(argc != val) { \
printf("error args\n"); \
return -1; \
}
#define ERROR_CHECK(ret, retVal, funcName) { \
if(ret == retVal) { \
perror(funcName); \
return -1; \
} \
}
#define THREAD_ERROR_CHECK(ret, funcName) \
do { \
if (0 != ret) { \
printf("%s : %s\n", funcName, strerror(ret)); \
} \
}while(0)
//父进程管理子进程的数据结构
typedef struct {
short flag;
int pipefd;
pid_t pid;
}process_data_t, *pProcess_data_t;
typedef struct
{
int len;
char buf[1000];
}Train_t,*pTrain_t;
int makeChild(int processNum, pProcess_data_t pData);
int childFunc(int pipefd);
int tcpInit(char *ip, char *port, int *sockFd);
int epollAddFd(int fd, int epfd);
int sendFd(int pipeFd, int fd,char flag);
int recvFd(int pipeFd, int *fd,char *flag);
int recvCycle(int sockfd,void *buf,int totalLen);
int transFile(int clienFd);
TCP套接字初始化
tcpInit.c
#include "process_pool.h"
int tcpInit(char *ip, char *port, int *sockFd)
{
int sfd = socket(AF_INET, SOCK_STREAM, 0);
ERROR_CHECK(sfd, -1, "socket");
struct sockaddr_in serAddr;
memset(&serAddr, 0, sizeof(serAddr));
serAddr.sin_family = AF_INET;
serAddr.sin_addr.s_addr = inet_addr(ip);
serAddr.sin_port = htons(atoi(port));
//设置套接口地址可重用
int reuse = 1; // 变量大于0,设置的选项生效
setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse));
int ret = 0;
ret = bind(sfd, (struct sockaddr*)&serAddr, sizeof(serAddr));
ERROR_CHECK(ret, -1, "bind");
ret = listen(sfd, 10);
ERROR_CHECK(ret, -1, "listen");
*sockFd = sfd;
return 0;
}
主进程下,创建子进程,利用子进程创建进程池child.c
#include "process_pool.h"
int makeChild(int processNum, pProcess_data_t pData)
{
int sfd[2];
pid_t childPid = 0;
for(int i = 0; i < processNum; ++i){
socketpair(AF_LOCAL, SOCK_STREAM, 0, sfd);
childPid = fork();
if(0 == childPid){
close(sfd[1]);
childFunc(sfd[0]);
exit(0);
}
close(sfd[0]);
pData[i].flag = 0;
pData[i].pid = childPid;
pData[i].pipefd = sfd[1];
}
return 0;
}
int childFunc(int pipefd)
{
int clienFd = 0;
while(1){
//接收父进程传来的newFd
recvFd(pipefd, &clienFd,0);
//写管道,使管道就绪,让父进程把自己的状态置为非忙碌的
transFile(clienFd);
write(pipefd, "a", 1);
}
return 0;
}
epoll监听的封装epollAddFd.c
#include "process_pool.h"
int epollAddFd(int fd, int epfd)
{
struct epoll_event event;
memset(&event, 0, sizeof(event));
event.events = EPOLLIN;
event.data.fd = fd;
epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &event);
return 0;
}
子进程下传递fd给进程池
sendFd
#include "process_pool.h"
int sendFd(int pipeFd, int fd)
{
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
struct iovec iov;
memset(&iov, 0, sizeof(iov));
char buf[8] = {0};
strcpy(buf, "hi");
iov.iov_base = buf;
iov.iov_len = strlen(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
int len = CMSG_LEN(sizeof(int));
struct cmsghdr *cmsg = (struct cmsghdr*)calloc(1, len);
cmsg->cmsg_len = len;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
*(int*)CMSG_DATA(cmsg) = fd;
msg.msg_control = cmsg;
msg.msg_controllen = len;
sendmsg(pipeFd, &msg, 0);
return 0;
}
进程池接收文件描述符和信息
#include "process_pool.h"
int recvFd(int pipeFd, int *fd)
{
struct msghdr msg;
memset(&msg, 0, sizeof(msg));
struct iovec iov;
memset(&iov, 0, sizeof(iov));
char buf[8] = {0};
strcpy(buf, "hi");
iov.iov_base = buf;
iov.iov_len = strlen(buf);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
int len = CMSG_LEN(sizeof(int));
struct cmsghdr *cmsg = (struct cmsghdr*)calloc(1, len);
cmsg->cmsg_len = len;
cmsg->cmsg_level = SOL_SOCKET;
cmsg->cmsg_type = SCM_RIGHTS;
msg.msg_control = cmsg;
msg.msg_controllen = len;
recvmsg(pipeFd, &msg, 0);
*fd = *(int*)CMSG_DATA(cmsg);
return 0;
}
进程池中的进程负责传输文件
#include "process_pool.h"
void sigfunc(int signum)
{
printf("sig is comming\n");
}
int transFile(int clienFd)
{
signal(SIGPIPE, sigfunc);
//使用私有协议发送数据,人为的规定发送数据的边界
Train_t train;
memset(&train, 0, sizeof(train));
int fd = open("file", O_RDWR);
//存储文件名长度
train.len = 4;
strcpy(train.buf, "file");
//发送文件名
send(clienFd, &train, 4 + train.len, 0);
while(1){
int ret = read(fd, train.buf, sizeof(train.buf));
train.len = ret;
//send以一个已经断开的连接,会返回-1, 在次send的时候,会收到SIGPIPE信号
//终止子进程
int ret1 = send(clienFd, &train, 4 + train.len, 0);
if(0 == ret){
break;
}
if(-1 == ret1){
printf("client exit\n");
break;
}
}
return 0;
}
主函数
#include "process_pool.h"
int pipe1[2];
void sigFunc(int sig)
{
printf("sig \n");
write(pipe1[1],&sig,4);
//把、写入管道
}
int main(int argc, char** argv)
{
//ip,port, processNum;
int processNum = atoi(argv[3]);
pProcess_data_t pData = (pProcess_data_t)calloc(processNum,sizeof(process_data_t));
makeChild(processNum,pData);
//循环创建子进程
pipe(pipe1);
signal(SIGUSR1,sigFunc);
int sfd;
tcpInit(argv[1],argv[2],&sfd);
//将sfd传出
int epfd = epoll_create(1);
epollAddFd(sfd,epfd);
//将文件描述符纳入监听
epollAddFd(pipe1[0],epfd);
//把管道的读端纳入监听,如果是发送信号了,读端肯定就有数据了,证明来信号了
for(int i = 0 ;i< processNum; i++)
{
//循环将管道的读端纳入监听
epollAddFd(pData[i].pipefd,epfd);
}
int newfd;
struct epoll_event evs[2];
int num;
while(1)
{
num = epoll_wait(epfd,evs,2,-1);
for(int i = 0 ; i<num; i++)
{
if(evs[i].data.fd == sfd)
{
newfd = accept(sfd,NULL,NULL);
for(int j = 0 ;j< processNum ; j++)
{
if(pData[j].flag == 0)
{
sendFd(pData[j].pipefd, newfd,0);
break;
}
}
close(newfd);
}
if(evs[i].data.fd == pipe1[0])
{
//退出1,暴力
/*
for(int j=0 ;j<processNum; j++)
{
kill(pData[j].pid,SIGUSR1);
}
*/
for(int j=0 ;j<processNum; j++)
{
//循环遍历所有子进程
sendFd(pData[i].pipefd,0,1);
//发送标志位1过去,证明要关闭了
}
for(int j = 0;j<processNum; j++)
{
int s;
wait(&s);//捕获退出状态
if(WIFEXITED(s))
{
printf("num =%d \n",WEXITSTATUS(s));
}
}
exit(0);//主进程也跟着完蛋了
}
else
{
for(int j = 0 ;j< processNum ; j++)
{
if(pData[j].pipefd == evs[i].data.fd)
{
char buf[4] = {0};
read(pData[j].pipefd,buf,sizeof(buf));
pData[j].flag = 0;
break;
}
}
}
}
}
}