How to IPC between PHP clients and a C Daemon Server?

后端 未结 7 907
春和景丽
春和景丽 2020-12-02 13:32

and thanks for taking a look at the question.

The background
I have several machines that continuously spawn multiple (up to 300) PHP console sc

相关标签:
7条回答
  • 2020-12-02 14:00

    nanomsg is coded in plain C so I guess it is better suited for your needs than Thrift and ZeroMQ that are coded in C++.

    It has wrappers for many languages including PHP.

    Here is a working example using the NN_PAIR protocol: (you can use NN_REQREP too)

    client.php

    <?php
    
    $sock = new Nanomsg(NanoMsg::AF_SP, NanoMsg::NN_PAIR);
    
    $sock->connect('ipc:///tmp/myserver.ipc');
    
    $sock->send('Hello World!', 0);
    
    $sock->setOption(NanoMsg::NN_SOL_SOCKET, NanoMsg::NN_RCVTIMEO, 1000);
    
    $data = $sock->recv(0, 0);
    
    echo "received: " . $data . "\n";
    
    ?>
    

    server.c

    #include <stdio.h>
    #include <string.h>
    #include <nanomsg/nn.h>
    #include <nanomsg/pair.h>
    
    #define address "ipc:///tmp/myserver.ipc"
    
    int main() {
      unsigned char *buf = NULL;
      int result;
      int sock = nn_socket(AF_SP, NN_PAIR);
      if (sock < 0) puts("nn_socket failed");
    
      if (nn_bind(sock, address) < 0) puts("bind failed");
    
      while ((result = nn_recv(sock, &buf, NN_MSG, 0)) > 0) {
        int i, size = strlen(buf) + 1;  // includes null terminator
        printf("RECEIVED \"%s\"\n", buf);
        for (i = 0; buf[i] != 0; i++)
          buf[i] = toupper(buf[i]);
        nn_send(sock, buf, size, 0);
        nn_freemsg(buf);
      }
      nn_shutdown(sock, 0);
      return result;
    }
    
    0 讨论(0)
  • 2020-12-02 14:02

    The "problem" (maybe not?) is that there can certainly be many consumers/producers on the SysV MQs. Though perfectly possible for what you're doing if you don't necessarily have an m:n need on the producer:consumer to resources model, you have a request/response model here.

    You can get some strange hangups with SysV MQ as it is.

    First, are you sure that INET sockets aren't fast enough for you? A quick PHP example using unix domain sockets is at http://us.php.net/socket-create-pair (just as code example of course, use socket_create() for the PHP endpoint).

    0 讨论(0)
  • 2020-12-02 14:04

    You could also load the data structure into shared memory using PHP's shared memory functions http://www.php.net/manual/en/book.shmop.php.

    Oh, it's not obvious from the documentation but the coordinating variable is $key in shmop_open. Every process needing access to the shared memory should have the same $key. So, one process creates the shared memory with $key. The other processes then can access that shared memory if they use the same $key. I believe you can choose whatever you like for $key.

    0 讨论(0)
  • 2020-12-02 14:17

    Here is a working example where the php script sends a request to a C daemon and then waits for the response. It uses Unix domain sockets in datagram mode so it is fast and simple.

    client.php

    <?php
    
    do {
      $file = sys_get_temp_dir() . '/' . uniqid('client', true) . '.sock';
    } while (file_exists($file));
    
    $socket = socket_create(AF_UNIX, SOCK_DGRAM, 0);
    
    if (socket_bind($socket, $file) === false) {
      echo "bind failed";
    }
    
    socket_sendto($socket, "Hello World!", 12, 0, "/tmp/myserver.sock", 0);
    
    if (socket_recvfrom($socket, $buf, 64 * 1024, 0, $source) === false) {
      echo "recv_from failed";
    }
    echo "received: [" . $buf . "]   from: [" . $source . "]\n";
    
    socket_close($socket);
    unlink($file);
    ?>
    

    server.c

    #include <stdio.h>
    #include <sys/un.h>
    #include <sys/socket.h>
    
    #define SOCKET_FILE "/tmp/myserver.sock"
    #define BUF_SIZE    64 * 1024
    
    int main() {
      struct sockaddr_un server_address = {AF_UNIX, SOCKET_FILE};
    
      int sock = socket(AF_UNIX, SOCK_DGRAM, 0);
      if (sock <= 0) {
          perror("socket creation failed");
          return 1;
      }
    
      unlink(SOCKET_FILE);
    
      if (bind(sock, (const struct sockaddr *) &server_address, sizeof(server_address)) < 0) {
          perror("bind failed");
          close(sock);
          return 1;
      }
    
      while (1) {
        struct sockaddr_un client_address;
        int i, numBytes, len = sizeof(struct sockaddr_un);
        char buf[BUF_SIZE];
    
        numBytes = recvfrom(sock, buf, BUF_SIZE, 0, (struct sockaddr *) &client_address, &len);
        if (numBytes == -1) {
          puts("recvfrom failed");
          return 1;
        }
    
        printf("Server received %d bytes from %s\n", numBytes, client_address.sun_path);
    
        for (i = 0; i < numBytes; i++)
          buf[i] = toupper((unsigned char) buf[i]);
    
        if (sendto(sock, buf, numBytes, 0, (struct sockaddr *) &client_address, len) != numBytes)
          puts("sendto failed");
      }
    
    }
    
    0 讨论(0)
  • 2020-12-02 14:20

    Although I have never tried it, memcached along with an appropriate PHP extension ought to eliminate most of the grunt work.

    Clarification: I was implicitly assuming that if you did this, you would put the individual leaves of the trie into the memcache using flattened keys, ditching the trie. The feasibility and desirability of this approach, of course, depends on many factors, first and foremost being the data source.

    0 讨论(0)
  • I suspect Thrift is what you want. You'd have to write a little glue code to do PHP <-thrift-> C++ <-> C, but that would probably be more robust than rolling your own.

    0 讨论(0)
提交回复
热议问题