Inter-process communication of swoole_process

Source: Internet
Author: User
Blog has not been updated for a long time, the main focus of the six months on the toss Swoole, the company project also on-line several swoole services in the middleware, and recently also to go online a middleware. Swoole_server, swoole_process and so on are used more, now to slowly summarize.

As you can see from the swoole_process documentation, there are 3 modes of communication between the swoole_process processes:

    • 1. Piping pipe
    • 2. IPC Msgqueue
    • 3. Signal

The next step is to introduce the principle and implementation of each communication in detail.

1. Piping pipe

That's what it says in the plumbing documentation.

int swoole_process::__construct (mixed $function, $redirect _stdin_stdout = False, $create _pipe = True)

* $redirect _stdin_stdout, redirects the standard input and output of the subprocess. When this option is enabled, in-process echo will not print the screen, but is written to the pipeline. Reading the keyboard input changes to read data from the pipe. The default is blocking read. * $create _pipe, whether to create a pipeline, when $redirect_stdin_stdout is enabled, this option ignores the user parameter and is forced to true if there is no interprocess communication within the child process, it can be set to False

* $process object will automatically close the pipeline when it is destroyed, and will receive a close event if the pipe is monitored within the child process

* 1.7.22 or later allows you to set the type of pipeline, which defaults to Sock_stream streaming

* When the parameter $create_pipe is 2 o'clock, the pipe type will be set to Sock_dgram

int Swoole_process->write (String $data)

* Swoole The bottom layer uses a UNIX socket for communication, Unixsocket is the kernel implementation of full memory communication, without any IO consumption. In the 1 process write,1 process read, each read and write 1024 bytes of data in the test, 1 million communication takes only 1.02 seconds. * The default mode of pipeline communication is streaming, write writes data in read may be merged at the bottom. You can set the third parameter of the Swoole_process constructor to 2 to change the number of the reported type.

As you can see from the sections in the documentation above, there are two types of pipelines: sock_stream and Sock_dgram, which are the type parameters needed to build the socket. The pipe operator "|" is used in our most common Linux commands, and in standard UNIX programming, pipeline creation is also an anonymous pipe created through the function int pipe (int filedes[2]) , or through the int Mkfifo (const Char *pathname, mode_t mode) creates a named pipe that neither of these methods creates sock_* parameters.

Here is the code for creating a pipe from the swoole extension

if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "Z|bl", &callback, &redirect_stdin_and_stdout, & Pipe_type) = = FAILURE) {        return_false;} ... if (Pipe_type > 0) {    swpipe *_pipe = emalloc (sizeof (Swworker)); C2/>int Socket_type = Pipe_type = = 1? Sock_stream:sock_dgram;    if (Swpipeunsock_create (_pipe, 1, Socket_type) < 0)    {        return_false;    }     Process->pipe_object = _pipe;    Process->pipe_master = _pipe->getfd (_pipe, sw_pipe_master);    Process->pipe_worker = _pipe->getfd (_pipe, sw_pipe_worker);    Process->pipe = process->pipe_master;     Zend_update_property_long (Swoole_process_class_entry_ptr, Getthis (), Zend_strl ("pipe"), Process->pipe_ MASTERTSRMLS_CC);}

As can be seen from the above code, the pipe here is created by the function swpipeunsock_create , the following is the complete implementation of this function

int Swpipeunsock_create (swpipe *p, int blocking, int protocol) {INT ret;    Swpipeunsock *object = sw_malloc (sizeof (Swpipeunsock));        if (object = = NULL) {Swwarn ("malloc () failed.");    return sw_err;    } p->blocking = blocking;    ret = Socketpair (Af_unix, protocol, 0, object->socks); if (Ret < 0) {Swwarn ("Socketpair () failed.        Error:%s [%d] ", strerror (errno), errno);    return sw_err;            } else {//nonblock if (blocking = = 0) {swsetnonblock (object->socks[0]);        Swsetnonblock (Object->socks[1]);        } int sbsize = Swooleg.socket_buffer_size;        Swsocket_set_buffer_size (Object->socks[0], sbsize);         Swsocket_set_buffer_size (Object->socks[1], sbsize);        P->object = object;        P->read = Swpipeunsock_read;        P->write = Swpipeunsock_write;        P-&GT;GETFD = SWPIPEUNSOCK_GETFD;    P->close = Swpipeunsock_close; } return 0;}

From the above code can be very intuitive to see, is through the function Socketpair created a pair of connected (Unix family) nameless socket. In Linux, it is perfectly possible to use the socket as the file descriptor returned by the pipe, the only difference being that any one of the pair of file descriptors is readable and writable. So the communication between the main process and the child process is exactly the socket communication.

Related information:

Implementing bidirectional interprocess communication pipelines on Linux

Socketpair

2. IPC Msgqueue

BOOL Swoole_process->usequeue (int $msgkey = 0, int $mode = 2);

* $msgkey is the message queue key, the default is to use the Ftok (FILE) * $mode communication mode, the default is 2, for the scramble mode, all the created child processes will fetch data from the queue

* After using mode 2, the child process created cannot communicate individually, such as to a specific subprocess.

* $process object does not execute start, or it can perform push/pop push/Fetch data to the queue

* Message Queuing communication is not common with pipelines. Message Queuing does not support EventLoop, only synchronous blocking mode is used after Message Queuing

Above are some of the descriptions from the documentation. or directly see the source how to achieve

Static Php_method (swoole_process, usequeue) {    long msgkey = 0;    Long mode = 2;     if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "|ll", &msgkey, &mode) = = FAILURE)    {        Return_ FALSE;    }     Swworker *process = Swoole_get_object (Getthis ());     if (msgkey <= 0)    {#if php_major_version = = 7        Msgkey = Ftok (execute_data->func->op_array.filename-> Val, 0); #else        Msgkey = Ftok (EG (active_op_array)->filename, 0); #endif    }     swmsgqueue *queue = Emalloc ( sizeof (Swmsgqueue));    if (swmsgqueue_create (queue, 1, msgkey, 0) < 0)    {        return_false;    }    Queue->delete = 0;    Process->queue = queue;    Process->ipc_mode = mode;    Return_true;}

As you can see from the source, the default value of $msgkey is 0, and when its value is less than or equal to 0, the default value of Ftok (FILE)is used. Mode is not used directly here, but instead assigns it to the Ipc_mode property of the Process object.

But here we create the queue using swmsgqueue_create , which is the prototype of this function.

int Swmsgqueue_create (swmsgqueue *q, int blocking, key_tmsg_key, long type) {    int msg_id;    if (blocking = = 0)    {        q->ipc_wait = ipc_nowait;    }    else    {        q->ipc_wait = 0;    }    q->blocking = blocking;    msg_id = Msgget (Msg_key, Ipc_creat | O_excl | 0666);    if (msg_id < 0)    {        Swwarn ("Msgget () failed. Error:%s[%d] ", Strerror (errno), errno);        return sw_err;    }    else    {        q->msg_id = msg_id;        Q->type = type;    }    return 0;}

This code is very simple and creates a key of $msg_key and is a blocking msgqueue. Here is the complete msgqueue of the creation logic, when you do not set the default key, the system takes a default value as key, of course, you can also set any key according to your needs to create one or more msgqueue.

It says the first parameter $msgkey, and here's a look at the effect of the second parameter $mode. The above code assigns mode to the Ipc_mode property of the Process object, which is where it is used.

First look at data such as queue pop

Static Php_method (swoole_process, push) {    ...     struct    {        long type;        Char data[65536];    } message;     if (Zend_parse_parameters (Zend_num_args () tsrmls_cc, "s", &data, &length) = = FAILURE)    {        return_false;    }     ......     Message.type = process->id;    memcpy (message.data, data, length);     if (Swmsgqueue_push (Process->queue, (Swqueue_data *) &message, Length) < 0)    {        Php_error_docref ( NULL tsrmls_cc, E_warning, "msgsnd () failed. Error:%s[%d] ", Strerror (errno), errno);        Return_false;    }    Return_true;}

As you can see from the code above, the value passed in when we call push is put into a message struct and then called Swmsgqueue_push to queue the data.

Here is the implementation of Swmsgqueue_push

int Swmsgqueue_push (Swmsgqueue *q, swqueue_data *in, int length) {    int ret;     while (1)    {        ret = msgsnd (q->msg_id, in, length, q->ipc_wait);         if (Ret < 0)        {            if (errno = = eintr)            {                continue;            }            else if (errno = = Eagain)            {                Swyield ();                Continue;            }            else            {                return-1;            }        }        else        {            return ret;        }    }    return 0;}

The code here is simple, calling the system to call msgsnd to put the data into the queue.

Now look at the data out queue pop

Static Php_method (swoole_process, pop) {    ...     struct    {        long type;        Char Data[sw_msgmax];    } message;     if (Process->ipc_mode = = 2)    {        message.type = 0;    }    else    {        Message.type = process->id;    }     int n = swmsgqueue_pop (Process->queue, (Swqueue_data *) &message, maxsize);    if (n < 0)    {        php_error_docref (NULL tsrmls_cc, e_warning, "MSGRCV () failed. Error:%s[%d] ", Strerror (errno), errno);        Return_false;    }    Sw_return_stringl (Message.data, N, 1);}

Seeing here, we finally see the effect of the $mode parameters we passed in before. If we say that the default value in the document is 2, the type of the message struct is set to 0, otherwise the ID of the current process is taken. And here's one to say, every process is a constructor that sets its own property ID to a value when its object is new, which is a self-increment counter that queues an initialized process object, So the value of each process ID is not the same.

The point is to see swmsgqueue_pop .

int Swmsgqueue_pop (Swmsgqueue *q, swqueue_data *data, int length) {    int flag = q->ipc_wait;    Long type = data->mtype;     Return MSGRCV (q->msg_id, data, length, type, flag);}

See, type is the 4th parameter required by the MSGRCV system call. The following is an explanation of this parameter:

1. = 0: Receive the first message

2. >0: The first message that receives a type equal to Msgtyp

3.<0: The first message that receives a type equal to or less than the absolute value of Msgtyp

So now the analysis, swoole_process use msgqueue words is quite flexible, so that you can do whatever you want to achieve your needs. Multi-queue, single-queue, single-queue different types, such a combination of benefits is only you can not think of, there is no swoole_process implementation of the communication model.

Reference Documentation:

Msgget

MSGSND & MSGRCV

3. Signal

This is the most common signal. So this is not as good as the above two details. Swoole_process gives a function to set the asynchronous listener signal.

BOOL Swoole_process::signal (int $signo, mixed $callback);

* This method is based on SIGNALFD and EventLoop is asynchronous IO and cannot be used in a synchronization program

* Synchronous blocking programs can use the pcntl_signal provided by the pcntl extension

* $callback If NULL indicates the removal of the signal listener

The document shows that this function can only be used in asynchronous programs, so there is no more explanation. And about how to use Pcntl_signal,rango in the synchronization program has been explained in the blog, so directly see the line "PHP official pcntl_signal performance is very poor"

Well, after finishing, my mind is clearer.

  • Contact Us

    The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

    If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.