PHP中的CGI实现
PHP的CGI实现了Fastcgi协议,是一个TCP或UDP协议的服务器接受来自Web服务器的请求,当启动时创建TCP/UDP协议的服务器的socket监听,并接收相关请求进行处理。随后就进入了PHP的生命周期:模块初始化,sapi初始化,处理PHP请求,模块关闭,sapi关闭等就构成了整个CGI的生命周期。
以TCP为例,在TCP的服务端,一般会执行这样几个操作步骤:
1 调用socket函数创建一个TCP用的流式套接字
2 调用bind函数将服务器的本地地址与前面创建的套接字绑定
3 调用listen函数将创建的套接字作为监听,等待客户端发起的连接,当客户端有多个连接连接到这个套接字时,可能需要排队处理。
4 服务器进程调用accept函数进入阻塞状态,直到有客户进程调用connect函数而建立一个连接
5 当与客户端创建连接后,服务器调用read_stream函数读取客户的请求
6 处理完数据后,服务器调用write函数向客户端发送应答
如下图:
PHP的CGI实现从cgi_main.c文件的main函数开始,在main函数中调用了定义在fastcgi.c文件中的初始化,监听等函数。对比TCP流程,我们查看PHP对TCP协议的实现,虽然PHP本身也实现了这些流程,但是在main函数中一些过程被封装成一个函数实现。对应TCP的操作流程,PHP首先会执行创建socket,绑定套接字,创建监听:
if(bindpath){
fcgi_fd = fcgi_listen(bindpath,128);//实现socket监听,调用fcgi_init初始化
}
在fastcgi.c文件中,fcgi_listen函数主要用于创建、绑定socket并开始监听,它走完了前面听列TCP流程的前三个阶段,
if((listen_socket = socket(sa.sa.sa_family,SOCK_STREAM))<0 || bind(listen_socket,(struct sockaddr *) &sa,sock_len) <0 || listen(listen_socket,backlog)<0){
}
当服务端初始化完成后,进程调用accept函数进入阻塞状态,在main函数中我们看到如下代码:
while(parent){
do{
pid = fork();//生成新的子进程
switch(pid){
parent = 0;
// don't catch our signals
sigaction(SIGTERM,&old_term,0);//终止信号,
}
}while(parent && (runing < children));
}