php socket连接多个设备,如何spawn多个外部程序并且accept同一个socket

缘起

学习fastcgi的时候,多个fcgi进程的启动和管理是个无法回避的问题;有一个叫做spawn-fcgi的程序,可以启动多个php-cgi进程,并且同时accept同一个socket,因为spawn-fcgi和php-cgi是两个项目中的程序,那么他们是如何配合的如此默契的呢?

分析

从代码来看,spawn-fcgi负责lisent一个socket,然后开始fork指定数量的子进程,每个子进程中先把socket的fd复制到FCGI使用的fd(似乎是约定好的一个fd),然后就把后续的事情通过exec交给外部的进程(如:php-cgi)了

下面看一下PHP中fastcgi的相关逻辑, 文件 sapi/cgi/fastcgi.c 中的 int fcgi_init(void);函数体现了如何识别是否fastcgi的逻辑,大致意思为: 如果标准输入为一个socket(不是fileno),则认为是fastcgi,代码片段如下:

#ifdef _WIN32

if ((GetStdHandle(STD_OUTPUT_HANDLE) == INVALID_HANDLE_VALUE) &&

(GetStdHandle(STD_ERROR_HANDLE) == INVALID_HANDLE_VALUE) &&

(GetStdHandle(STD_INPUT_HANDLE) != INVALID_HANDLE_VALUE)) {

char *str;

DWORD pipe_mode = PIPE_READMODE_BYTE | PIPE_WAIT;

HANDLE pipe = GetStdHandle(STD_INPUT_HANDLE);

SetNamedPipeHandleState(pipe, &pipe_mode, NULL, NULL);

str = getenv("_FCGI_SHUTDOWN_EVENT_");

if (str != NULL) {

HANDLE shutdown_event = (HANDLE) atoi(str);

if (!CreateThread(NULL, 0, fcgi_shutdown_thread,

shutdown_event, 0, NULL)) {

return -1;

}

}

str = getenv("_FCGI_MUTEX_");

if (str != NULL) {

if (str != NULL) {

HANDLE shutdown_event = (HANDLE) atoi(str);

if (!CreateThread(NULL, 0, fcgi_shutdown_thread,

shutdown_event, 0, NULL)) {

return -1;

}

}

str = getenv("_FCGI_MUTEX_");

if (str != NULL) {

fcgi_accept_mutex = (HANDLE) atoi(str);

}

return is_fastcgi = 1;

} else {

return is_fastcgi = 0;

}

#else

errno = 0;

if (getpeername(0, (struct sockaddr *)&sa, &len) != 0 && errno == ENOTCONN) {

fcgi_setup_signals();

return is_fastcgi = 1;

} else {

return is_fastcgi = 0;

}

#endif

427

428

429

430

431

432

433

434

435

436

437

438

439

440

441

442

443

444

445

446

447

448

449

450

451

452

453

454

455

456

457

458

459

460

461

462

463

464

465

466

467

468

469

470

#ifdef _WIN32

if((GetStdHandle(STD_OUTPUT_HANDLE)==INVALID_HANDLE_VALUE)&&

(GetStdHandle(STD_ERROR_HANDLE)  == INVALID_HANDLE_VALUE) &&

(GetStdHandle(STD_INPUT_HANDLE)  != INVALID_HANDLE_VALUE)) {

char *str;

DWORDpipe_mode=PIPE_READMODE_BYTE|PIPE_WAIT;

HANDLEpipe=GetStdHandle(STD_INPUT_HANDLE);

SetNamedPipeHandleState(pipe,&pipe_mode, NULL, NULL);

str=getenv("_FCGI_SHUTDOWN_EVENT_");

if(str!=NULL){

HANDLEshutdown_event=(HANDLE)atoi(str);

if(!CreateThread(NULL,0,fcgi_shutdown_thread,

shutdown_event,0,NULL)){

return-1;

}

}

str=getenv("_FCGI_MUTEX_");

if(str!=NULL){

if(str!=NULL){

HANDLEshutdown_event=(HANDLE)atoi(str);

if(!CreateThread(NULL,0,fcgi_shutdown_thread,

shutdown_event,0,NULL)){

return-1;

}

}

str=getenv("_FCGI_MUTEX_");

if(str!=NULL){

fcgi_accept_mutex=(HANDLE)atoi(str);

}

returnis_fastcgi=1;

}else{

returnis_fastcgi=0;

}

#else

errno=0;

if(getpeername(0,(structsockaddr*)&sa, &len) != 0 && errno == ENOTCONN) {

fcgi_setup_signals();

returnis_fastcgi=1;

}else{

returnis_fastcgi=0;

}

#endif

注意其中 getpeername(…)的使用,如果 errno == ENOTCONN 才可能认为是fastcgi,那么,如果刚好该socket处于连接状态不就不能视为fastcgi环境了吗?  或许吧

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值