2

Debian Lenny 32 ビットで Apache2.2 サーバー + PHP 5.2 を実行しています。「単純な」php モジュール拡張機能を C で作成しました。この拡張機能は 1 つのことを行っています: ソケットを介して小さな「エコー サーバー」を呼び出し、結果を待ちます (両側で「A」を送受信)。

prefork-mpm モデルに入って、ソケットをグローバル var PHP 構造に設定しました。したがって、グローバルに拡張ソースは次のように聞こえます。

mymodule.h で

    ZEND_BEGIN_MODULE_GLOBALS(hello)
        int socket;
    ZEND_END_MODULE_GLOBALS(hello)

    #ifdef ZTS
    #define HELLO_G(v) TSRMG(hello_globals_id, zend_hello_globals *, v)
    #else
    #define HELLO_G(v) (hello_globals.v)
    #endif

mymodule.c で

...
static int sock_create(char *address, int port, SA_IN *servaddr)
{
   int s;

   s = socket(AF_INET, SOCK_STREAM, 0);

   if (!s)
     return 0;

   memset(servaddr, 0, sizeof(SA_IN));
   servaddr->sin_family = AF_INET;
   servaddr->sin_port = htons((unsigned short)port);
   servaddr->sin_addr.s_addr = inet_addr(address);

   return s;
}




int send_recv(int sock, char ch)
 {
   int r;
   char tmp[2];

   tmp[0]=ch;
   tmp[1]=0;

   r = send(sock, 'A', 1, 0);

   if (r<=-1)
     return -1;

   r = recv(sock, tmp, 1, 0);

   if (r<=-1)
     return -2;

   return (int) tmp[0];

 }



 PHP_FUNCTION(cmd_echo)
 {
   int item, r=0;
   SA_IN addr;

   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &item)==FAILURE)
     WRONG_PARAM_COUNT;


   if (HELLO_G(sa)==0)
   {
     HELLO_G(sa) = sock_create("server_ip", 4500, &addr);

     r = connect(HELLO_G(sa), (SA *) &addr, sizeof(SA));

     send_recv(HELLO_G(sa), 'a');
     RETURN_LONG(6);
   }
   else
   {
     send_recv(HELLO_G(sa), 'b');     // <---- trouble here, hangs...
     RETURN_LONG(7);
   }

   RETURN_LONG(1);
  }

完璧ですね... Apache が新しいプロセスを fork するたびに、新しい接続 (sa==0) を作成します私はそれについて確信しています)ソケットを作成せずにサーバーにデータを送信します。ある種の「ソケットプール」のように振る舞うだけです

しかし、ここで問題が発生します...

理由は不明ですが、Apache が開いているソケットを再利用しようとすると、send() コマンドで send_recv() がハングします。確かに、ソケットはブロッキング モードになっていますが、なぜこのような動作になるのでしょうか?

(ちなみに、同じコードを (もちろん PHP コードなしで) 複数の send_recv を持つ実行可能ファイルに実行すると、すべてが完全に機能します!)

Apache がソケットをロックしているようです !??

何か案が ?

4

0 に答える 0