简 易 版 的 进 程 池 模 型 学 习
简 易 版 的 进 程 池 模 型 学 习
#include<sys/stat.h>
#include <sys/stat.h>
#include<errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include<sys/wait.h>#define FILENAME "file"typedef struct{ //维护子进程的数据结构pid_t pid;int tfds;short busy;
}child,*pchild; typedef struct{ //网络数据发送的数据结构int len;char buf[1000];
}train,*ptrain;void send_fd(int fdw,int fd);
void recv_fd(int fdr,int* fd);
void make_child(pchild p,int len);
void child_handle(int fdr);
void send_data(int );
int send_n(int ,char *,int);
int recv_n(int,char *,int);
#include"func.h"int exitfds[2]; //退出拉起管道
int exit_num=0; //用于退出时判断机制void set_status(int fd)
{int status=fcntl(fd,F_GETFL);status=status|O_NONBLOCK;fcntl(fd,F_SETFL,status);
}void sighandle(int signum)
{write(exitfds[1],"over",4);
}int main(int argc,char **argv)
{ pipe(exitfds);signal(SIGINT,sighandle);if(4!=argc){perror("error argcs!\nplease enter IP SOCKET proccess_num\n");return -1;}int child_len=atoi(argv[3]);//首先为每个子进程动态申请空间,用指针实现数组效果pchild p=(pchild)calloc(child_len,sizeof(child)); //创建子进程,并初始化数据结构,//封装成一个Init函数make_child(p,child_len);int sfd;sfd=socket(AF_INET,SOCK_STREAM,0);if(sfd==-1){perror("socket");return -1;}struct sockaddr_in ser;ser.sin_addr.s_addr=inet_addr(argv[1]);ser.sin_port=htons(atoi(argv[2]));ser.sin_family=AF_INET;int ret;ret=bind(sfd,(struct sockaddr *)&ser,sizeof(ser));if(-1==ret){perror("bind");return -1;}int epfd=epoll_create(1); //创造一个epfd的句柄struct epoll_event event,*evs;evs=(struct epoll_event *)calloc(child_len+1,sizeof(struct epoll_event));memset(&event,0,sizeof(event));event.data.fd=sfd;event.events=EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_ADD,sfd,&event);int i;for(i=0;i<child_len;i++) //监管注册每个子进程的描述符管道{event.data.fd=p[i].tfds;event.events=EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_ADD,p[i].tfds,&event);}listen(sfd,child_len);int j,ret1,newfd;char flag[6];static int once=0;set_status(exitfds[0]);while(1){ret=read(exitfds[0],flag,sizeof(flag));if(ret>0){if(0==exit_num){printf("exerting quit action--please wait····\n");event.data.fd=sfd; //不在接受连接event.events=EPOLLIN;epoll_ctl(epfd,EPOLL_CTL_DEL,sfd,&event);for(i=0;i<child_len;i++){printf("正在处理子进程p[i].pid=%d ",p[i].pid);printf("\n");kill(p[i].pid,SIGKILL);}wait(NULL);printf("you have quited\n");return(0);}else{printf("请等待,有客户正在交易···\n"); }}ret1=epoll_wait(epfd,evs,child_len+1,-1);for(i=0;i<ret1;i++){ //妈的,又他妈犯这种错误了if(evs[i].data.fd==sfd) //网络请求到达{newfd=accept(sfd,NULL,NULL);//找到一个空闲的子进程,并且将newfd发送给它for(j=0;j<child_len;j++){if(p[j].busy==0){//通过tcp管道发送newfd给子进程send_fd(p[j].tfds,newfd); exit_num++;p[j].busy=1;printf("find a not busy proccess,send newfd success!\n");break;}}close(newfd); //关闭父进程对newfd的引用计数}//监听子进程的tcp管道的发送完成信息for(j=0;j<child_len;j++) {if(evs[i].data.fd==p[j].tfds){//read(p[j].tfds,&flag,sizeof(flag));char buf[15]={0};read(p[j].tfds,buf,sizeof(buf));printf("%s\n",buf);//read(p[j].tfds,&flag,sizeof(flag));p[j].busy=0;exit_num--;printf("child proccess %d is not busy!\n",j);if(0==exit_num){printf("Are you stall want to finish this deal,please push Ctrl+C\n");}}}}}
}
#include"func.h"/*首先,要创建len个子进程,就会用到fork( )函数,于是,必须把父进程和子进程分别开来,一个父进程,len个子进程。
其次,初始化是针对定义的数据结构初始化,有:
1、每个子进程在fork创建之后需要根据返回值保存自己的pid.
2、对于全双工的TCP管道,需要用socketpair( )函数初始化
3、刚开始时,将其每个子进程的busy位置为0,表示空闲
对于子进程,必须让它在循环里面持续发送,从父进程接收任务,父进程将到发送数据
,再到发送完,通知父进程,可以通过写一个flag,然后父进程将其busy改为0,
表示空闲。
*/
void child_handle(int fdr)
{int newfd;char flag[6]={0};strcpy(flag,"over");while(1){recv_fd(fdr,&newfd);send_data(newfd);printf("I am child,send success!\n");write(fdr,&flag,sizeof(flag));//write(fdr,"hello",5);}
}void make_child(pchild p,int len)
{int fds[2],i,ret;pid_t pid;for(i=0;i<len;i++){ret=socketpair(AF_LOCAL,SOCK_STREAM,0,fds);pid=fork();if(0==pid){close(fds[1]);child_handle(fds[0]);//p[i].tfds=fds[0]; 将fds[0]端留给子进程} //让其子进程在里面循环,不出来close(fds[0]);p[i].pid=pid; //获取子进程的pidp[i].busy=0; //置为空闲p[i].tfds=fds[1]; //将管道的一端传递给主进程}
}
#include "func.h"void send_fd(int fdw,int fd)
{struct msghdr msg;memset(&msg,0,sizeof(msg));struct cmsghdr *cmsg;int len=CMSG_LEN(sizeof(int));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;char buf1[10]="hello";char buf2[10]="world";struct iovec iov[2];iov[0].iov_base=buf1;iov[0].iov_len=5;iov[1].iov_base=buf2;iov[1].iov_len=5;msg.msg_iov=iov;msg.msg_iovlen=2;int ret=sendmsg(fdw,&msg,0);if(-1==ret){perror("sendmsg");return;}
}
void recv_fd(int fdr,int* fd)
{struct msghdr msg;memset(&msg,0,sizeof(msg));struct cmsghdr *cmsg;int len=CMSG_LEN(sizeof(int));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;char buf1[10]="hello";char buf2[10]="world";struct iovec iov[2];iov[0].iov_base=buf1;iov[0].iov_len=5;iov[1].iov_base=buf2;iov[1].iov_len=5;msg.msg_iov=iov;msg.msg_iovlen=2;int ret=recvmsg(fdr,&msg,0);if(-1==ret){perror("sendmsg");return;}*fd=*(int*)CMSG_DATA(cmsg);
}
#include"func.h"void send_data(int newfd)
{train t;memset(&t,0,sizeof(t));strcpy(t.buf,FILENAME);t.len=strlen(FILENAME);printf("the strcpy t.buf is %s, len =%d\n",t.buf,t.len);//先发文件名int ret;ret=send_n(newfd,(char *)&t,t.len+4);if(ret==-1){perror("send");return;}int fd=open(FILENAME,O_RDONLY);if(-1==fd){perror("open");return;}struct stat filestat;fstat(fd,&filestat);t.len=sizeof(long);memcpy(t.buf,&filestat.st_size,sizeof(filestat.st_size));send_n(newfd,(char*)&t,4+t.len);while(memset(t.buf,0,sizeof(t.buf)),(t.len=read(fd,t.buf,sizeof(t.buf)))>0){send_n(newfd,(char *)&t,t.len+4);}t.len=0;send_n(newfd,(char *)&t,4+t.len);close(newfd);close(fd);
}
#include"func.h"int send_n(int sfd,char *p,int len)
{int total=0,ret;while(total<len){ret=send(sfd,p+total,len-total,0);//取出每一次发送了多少个total=total+ret;}return 0;
}int recv_n(int sfd,char *p,int len )
{int total=0,ret;while(total<len){ret=recv(sfd,p+total,len-total,0);total=total+ret;}return 0;
}
8、客户器端源代码
#include<time.h>
#include <sys/stat.h>
#include<errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/select.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <netdb.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/epoll.h>
#include<sys/wait.h>typedef struct{pid_t pid;int tfds;short busy;
}child,*pchild;void send_fd(int fdw,int fd);
void recv_fd(int fdr,int* fd);
void make_child(pchild p,int len);
void child_handle(int fdr);
int recv_n(int,char *,int);int send_n(int sfd,char *p,int len)
{int total=0,ret;while(total<len){ret=send(sfd,p+total,len-total,0);//取出每一次发送了多少个total=total+ret;}return 0;
}int recv_n(int sfd,char *p,int len )
{int total=0,ret;while(total<len){ret=recv(sfd,p+total,len-total,0);total=total+ret;}return 0;
}int main(int argc,char **argv)
{if(3!=argc){printf("error argcs!\n");return -1;}int sfd;sfd=socket(AF_INET,SOCK_STREAM,0);if(-1==sfd){perror("socket");return -1;}struct sockaddr_in ser;memset(&ser,0,sizeof(ser));int ret,ret1;ser.sin_family=AF_INET;ser.sin_port=htons(atoi(argv[2]));ser.sin_addr.s_addr=inet_addr(argv[1]);ret=connect(sfd,(struct sockaddr*)&ser,sizeof(ser));int len;char buf[1000]={0};recv_n(sfd,(char *)&len,sizeof(len)); //先接受文件名recv_n(sfd,buf,len);int fd=open(buf,O_WRONLY|O_CREAT,0666);if(-1==fd){perror("open");return -1;}recv_n(sfd,(char *)&len,sizeof(len)); //在发送文件大小long file_len;recv_n(sfd,(char*)&file_len,len);long l=0;time_t now,check;time(&now);check=now;while(1){recv_n(sfd,(char *)&len,sizeof(len));if(len>0){l=l+len;memset(buf,0,sizeof(buf));recv_n(sfd,buf,len);//接受完后就要写到袭击者边新建的文件里write(fd,buf,len);//接受多少就写多少time(&now);if(now>check+1){printf("Now Data is %5.2f%s\r",100*(double)l/file_len,"%");fflush(stdout);check=now;}}else{printf("Down load successful!\n");break;}}close(fd);close(sfd);return 0;
}
简 易 版 的 进 程 池 模 型 学 习相关推荐
- 简 易 版 线 程 池 模 型 学 习
简 易 版 线 程 池 模 型 学 习 1.简易版线程池流程 1.初始化线程池 1.初始化队列, 队列头, 队列尾初始化, 队列能力初始化( 队列长度),队列锁 初始化线程池条件变量,给子线程赋入口函 ...
- 一期每日一GO群分享-flag、viper、协程池、异常处理
1.11 flag库 今天介绍一个库flag,命令行程序常用,用来接受参数的. var (intflag intboolflag boolstringflag string )func init() ...
- Golang的协程池设计
转载地址:https://studygolang.com/articles/15477 使用Go语言实现并发的协程调度池阉割版,本文主要介绍协程池的基本设计思路,目的为深入浅出快速了解协程池工作原理, ...
- 深入浅出 Golang 协程池设计
使用Go语言实现并发的协程调度池阉割版,本文主要介绍协程池的基本设计思路,目的为深入浅出快速了解协程池工作原理,与真实的企业协程池还有很大差距,本文仅供学习参考. 一.何为并发,Go又是如何实现并发? ...
- 白话 Golang 协程池
文章目录 1.何为并发 2.并发的好处 3.Go 如何并发 4.G-P-M 调度模型 5.Go 程的代价 6.协程池的作用 7.简易协程池的设计&实现 8.开源协程池的使用 9.小结 参考文献 ...
- 协程池gevent实现糗事百科爬取
标题 -协程池gevent实现糗事百科爬取 import gevent.monkey gevent.monkey.patch_all() from gevent.pool import Pool im ...
- Python-进程池的阻塞式(不能体现多进程的优势)
Python-进程池的阻塞式 先理解阻塞的概念 , 阻塞: 就是当本任务完成了,才能继续运行,后边的任务需要排队. 阻塞式的进程池的特点: 添加一个任务便执行一个任务,如果一个任务不结束,另一个任务进 ...
- 易人银行进账单打印软件 v1.1 免费
Welcome to my blog! <script language="javascript" src="http://avss.b15.cnwg.cn/cou ...
- [亲测,Success]Linux,VMware 安装+常用 命 令+网 络+进 程 管 理以及软件安装
安装Linux 1.环 境 安 装 1 安装VMware,课程中使用的是VMware10的版本 2 检测系统是否支持虚拟化 如果是win10系统,直接打开任务管理器查看 3 如果支持,查看虚拟化是否开 ...
最新文章
- 一个简单的socket程序-linux
- jquery之stop()的用法
- 性能测试vs负载测试vs压力测试
- idea中构造器和toString方法覆写的快捷键
- SAP Fiori应用里日期格式的显示奥秘
- Failed to execute
- c语言学生对老师的评教系统,学生对老师的评价
- 专题:数据自治开放(下)
- windows 导入表(动态调用)
- 利用hutool工具类导出Excel
- PowerShell中的环境变量
- 受半导体短缺及疫情影响,丰田已下调9月10月及当前财年产量预期
- 什么是计算机嵌套分类汇总,excel嵌套分类汇总 Excel表格中创建嵌套分类汇总和查看嵌套分类汇总明细的方法...
- 快速学懂pandas
- Revit 2021 族样板下载
- 无人机巡检系统设想路线
- J2EE是什么(一)
- Win10安装Ubuntu20.04双系统
- 物联网无线通信技术蓝牙、wifi、zigbee
- 日本电产尼得科Nidec研发出超薄直线振动马达
热门文章
- JavaScript语法(二)
- C语言第一节 C语言程序与开发工具
- IIS 7.0 部署MVC
- 程序一旦发觉写得不理想,那就得重构它
- 蓝桥杯第八届省赛JAVA真题----最大公共子串
- 罗小黑用flash做的_中影星美好看罗小黑战记正式定档!
- js中当等于最小值是让代码不执行_从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理...
- mysql 两个时间相差大于24小时的数据_MySQL 主从同步延迟的原因及解决办法(仅学习)...
- 计算机专业英语第07章,计算机专业英语电子教案第07章.ppt
- SpringMVC中使用@ResponseBody注解标注业务方法