Home > other >  IPC choice in PHP: Correct use of sockets
IPC choice in PHP: Correct use of sockets

Time:02-10

I have just dumped my earlier code, and am starting again from scratch, and would appreciate help ensuring that I am using sockets within PHP appropriately -- or whether another approach is warranted.

My main script is likely to be invoked from multiple processes concurrently, and for this task it is important that these requests are then 'collated' into a single work-stream, and processed in a linear fashion. I have what appears to be working code, below. What I would like to know is:

  • Are sockets the best approach here, or should I be using something else?
  • I found the plethora of different socket functions confusing, and not sure of advantages/disadvantages of each. Should I be using different functions?
  • Is my approach fundamentally 'correct'? I've tried to catch the 'obvious' problems, but have I thought of all of them?

I've heavily commented my code, which I hope helps to show what I would like help with.

<?php declare(strict_types=1);
error_reporting(E_ALL);

# This script will be invoked multiple times by different processes at random times.
# It is important that there is no risk of a race condition.

$socket = socket_create(AF_UNIX, SOCK_STREAM, 0);   // Left in at the moment, but unsure of best approach.
if ($socket === false) {
    $errorcode = socket_last_error();
    $errormsg = socket_strerror($errorcode);
    die("Couldn't create socket: [$errorcode] $errormsg\n");
}
//if (socket_bind($socket, '/tmp/IPC.sock')) {      // Earlier code, but stream_socket seemed easier.

$string = "Hello \n";
# First, we test to see if we are master, or client.
# Do this by attempting to create socket first
if (($sock = stream_socket_server('unix:///tmp/IPC.sock', $errorcode, $errormsg)) === false) {
    echo "Couldn't create socket: [$errorcode] $errormsg, therefore we must be the client.\n";
    if (($sock = stream_socket_client('unix:///tmp/IPC.sock', $errno, $errstr)) === false){
        echo "Oh dear -- something is wrong! \n";
        # Do what now??? Why would this happen? Is it a risk?
        unlink('/tmp/IPC.sock');
    }
    # We need to pass our string to the main instance, and quit as quickly as possible.
    # We don't want blocking, whilst threads are waiting for data to be received.
    fwrite($sock, "World\n");           // Send data.
    //echo stream_get_content($sock);   // We don't actually NEED a response, unless it helps
                                        // us to capture an error and take appropriate action.
    //stream_socket_shutdown($sock);    // Which one? Shutdown, or close?
    fclose($sock);
    echo "Done sending. \n";
} else {
    # No matter how many things are happening in other processes or threads, this section
    # should only ever be running once -- ensuring that we have strictly linear processing.
    echo "Socket created OK. \n";
    do_stuff ($string);
    # Now see if we're received any more work to do
    while ($conn = stream_socket_accept($sock,1)) { // Should we be using a fifo?
        $string= fread($conn, 1024);    // Actually, I'm interested in the string up to a "\n".
        do_stuff ($string);
    }
    //stream_socket_shutdown($sock);    // Which one? Shutdown, or close?
    fclose($sock);                      // Is there any risk of loss of incoming message at this point?
    unlink('/tmp/IPC.sock');
}

function do_stuff($string){
    echo "$string"; sleep(10);          // Main code here. Delay NOT exaggerated. CPU intensive.
}
# Clear up, and go home!
?>

For background (if of any interest), my previous attempt started with the line

use parallel\{Runtime, Channel, Events};

and created multiple threads to split the task into chunks. It worked great, until I realised that I'd created the perfect environment for a DoS as CPU went to 100% for prolonged periods as soon as I had made more than a few calls to the main script!

This could be a question for CodeReview.SE (https://codereview.meta.stackexchange.com/questions/5777/), because the question is open-ended, and I'm not certain that I have the correct approach here (and therefore opinions matter, as does "Correctness in unanticipated cases"). I'm posting here because of the post: Does being on-topic at another Stack Exchange site automatically make a question off-topic for Stack Overflow? states "Typically good CR questions are going to be too broad for SO". This question has specific goals: error trapping, CPU/Memory efficiency, and I am not 100% sure that my code "works as expected" (demonstrated by the unused remnants of socket_create(). So many functions that seem to do the same thing...), but I think my approach is broadly correct. It is specifically about IPC. There is no requirement for this code to be preserved verbatim. However, I'm happy for the question to be migrated by Mods if considered appropriate, to prevent cross-posting exactly the same question twice.

CodePudding user response:

  •  Tags:  
  • Related