php编写多进程web服务器
同样是使用select来实现,以上是php版本的源码,select IO模型复用主要是轮询方式监听文件描述符集,它依然是阻塞方式
具体可以参阅我做的说明。在此不再细说。网卡是怎么接收到数据,怎么把数据写入对应的sock的,到底怎么搞的,自己去看看。
在您阅读时:勿必了解下进程,进程组,进程调度,守护进程,前台进程,IO模型,网卡读写原理,中断系统,主机字节序和网络字节序列,tcp状态转移图,tcp抓包,socket地址类型,一些相关的数据结构如线性表的链表存储,二叉树插入和删除,以及平衡二叉树【红黑树】相关概念【以便你深入理解IO模型select和epoll的区别相关知识】
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int pids[10];
int main(int argc,char *argv[])
{
if(argc<2){
printf("useage:%s ip and port\n",basename(argv[0]));
exit(0);
}
char const *ip = argv[1];
int port = atoi(argv[2]);
struct sockaddr_in address;
bzero(&address,sizeof(address));
address.sin_family = AF_INET;
address.sin_port = htons(port);
inet_pton(AF_INET,ip,&address.sin_addr);
int sockfd = socket(PF_INET,SOCK_STREAM,0);//创建sock文件描述符,默认从最小的值开始,最小的值是多少,可以自己去想想进程启动时默认打开几个文件描述符,进程退出时又关闭了几个,想想进程启动前干什么了,在此不再多说,创建的sock会关联自己的接受和发送缓冲区
assert(sockfd>0);
int ret = bind(sockfd,(struct sockaddr*)&address,sizeof(address));//绑定ip和端口号
assert(ret!=-1);
ret = listen(sockfd,1024);//启用监听 并且处于LISTEN状态【tcp状态转移图自己去看本人前面说过的资料】
//文件描述集合初始化【或许你在linux玩上一阵子才好理解^_^】
fd_set readfds;
fd_set writefds;
fd_set exceptionfds;
fd_set reads;
fd_set writes;
fd_set exceptions;
FD_ZERO(&readfds);
FD_ZERO(&writefds);
FD_ZERO(&exceptionfds);
FD_ZERO(&reads);
FD_ZERO(&writes);
FD_ZERO(&exceptions);
int i;
int listenfd = sockfd;
FD_SET(sockfd,&readfds);
FD_SET(sockfd,&writefds);
FD_SET(sockfd,&exceptionfds);
struct timeval tv;
tv.tv_sec=0;
tv.tv_usec=0;
pid_t pid = fork();
if(pid<0|pid>0){
exit(0);
}
if(setsid()<0){
exit(0);
}
for(i=0;i<4;i++){
pid_t pid = fork();
if(pid<0){
exit(0);
}
else if(pid>0){
pids[i] = pid;
}else if(pid==0){
//FD_SET(sockfd,&readfds);
//FD_SET(sockfd,&writefds);
//FD_SET(sockfd,&exceptionfds);
int j;
srand((unsigned int)time(NULL));
while(1){
//FD_ZERO(&readfds);
//FD_ZERO(&writefds);
//FD_ZERO(&exceptionfds);
//FD_SET(sockfd,&readfds);
//FD_SET(sockfd,&writefds);
//FD_SET(sockfd,&exceptionfds);
reads = readfds;
writes = writefds;
exceptions = exceptionfds;
// printf("%d child process select\n",getpid());
//不用等,轮询【文件集合】时直接返回,tv为null时会阻塞【tv=0时直接返回】
int ret = select(listenfd+1,&reads,&writes,&exceptions,&tv);
// printf("ret=%d\n",ret);
if(ret<0){
printf("某进程%d退出\n",getpid());
exit(0);
}
if(ret==0){
continue;
}
for(j=0;j
if(FD_ISSET(j,&reads)){
if(j == sockfd){
struct sockaddr_in client;
socklen_t client_len = sizeof(client);
int connfd = accept(sockfd,(struct sockaddr*)&client,&client_len);
// if(connfd>0){
printf("%d child 当前的客户端文件描述符是:%d\n",getpid(),connfd);
FD_SET(connfd,&readfds);
FD_SET(connfd,&writefds);
FD_SET(connfd,&exceptionfds);
if(listenfd
printf("listenfd=%d\n",listenfd);
// }
// write(connfd,"hi",3);
}else{
char data[1024];
int len = read(j,data,sizeof(data));
if(len==0){
FD_CLR(j,&readfds);
FD_CLR(j,&writefds);
FD_CLR(j,&exceptionfds);
printf("555");
}
//FD_SET(j,&writefds);
printf("接受内容是:%s of %d\n",data,len);
}
}
if(FD_ISSET(j,&writes)){
char *data = "hello,world";
int len = write(j,data,strlen(data));
printf("某进程[%d]发送了%d的%s\n",getpid(),len,data);
FD_CLR(j,&readfds);
FD_CLR(j,&writefds);
FD_CLR(j,&exceptionfds);
close(j);
}
if(FD_ISSET(j,&exceptions)){
printf("出错了\n");
FD_CLR(j,&readfds);
FD_CLR(j,&writefds);
FD_CLR(j,&exceptionfds);
}
}
}
}
}
close(sockfd);
return EXIT_SUCCESS;
}
本作品采用《CC 协议》,转载必须注明作者和本文链接
只会php crud的渣渣