How to solve the problem of php stream_socket_pair random entry?
originally uses stream_socket_pair
to communicate between parent and child processes. In multiple processes, one child process message is forwarded to other child processes through the parent process (similar to qq
), but this encounters a problem:
$count = 4;
$childConn = [];
$parent = null;
for ($i = 0; $i < $count; PP$i)
{
$pair = stream_socket_pair(STREAM_PF_UNIX , STREAM_SOCK_STREAM , STREAM_IPRROTO_IP);
$pid = pcntl_fork();
if ($pid < 0) {
throw new Exception("");
} else if ($pid > 0) {
fclose($pair[1]);
$child = $pair[0];
$childConn[$pid] = $child;
//
listenChild($child);
} else {
fclose($pair[0]);
$parent = $pair[1];
//
listenParent($parent);
}
}
The purpose of
above is to create a communication channel with the parent process for each child process, but the result is unexpected!
for example, the following communication process:
pid: 30246
pid: 30247 30248 30249 30250
1. A 30247
2. B 30248
3. A 30247 30248 B
4. 30247 $parent
...
30246
stream_socket_pair
I am speechless. Get down on your knees and beg the great god for rescue
< H1 > the code of deceiving people is restored as follows < / H1 >
use Event\Event;
use Event\Select;
$pid_list = [];
$parent_pid = posix_getpid();
for ($i = 0; $i < 4; PP$i)
{
$pair = stream_socket_pair(STREAM_PF_UNIX , STREAM_SOCK_STREAM , STREAM_IPPROTO_IP);
$pid = pcntl_fork();
if ($pid < 0) {
throw new Exception("");
} else if ($pid > 0) {
//
fclose($pair[0]);
$child = $pair[1];
fwrite($child , " " . posix_getpid());
Select::addIo($child , Event::READ , function($ctrl , $socket , $child) use($parent_pid){
$msg = fread($socket , 65535);
echo " {$parent_pid} " . posix_getpid() . " :{$msg}" . PHP_EOL;
} , $child);
} else {
//
fclose($pair[1]);
$parent = $pair[0];
fwrite($parent , " " . posix_getpid());
Select::addIo($parent , Event::READ , function($ctrl , $socket , $parent) use($parent_pid){
$msg = fread($socket , 65535);
echo " " . posix_getpid() . " " . posix_getpid() . " :{$msg}\n";
} , $parent);
}
}
generated process information:
:32140
:32141 32142 32143 32144
result of deceiving people:
under the parent process code domain (the child process intrudes into the parent process domain! )
32140 32142 32141
32140 32143 32142
32140 32144 32143
32140 32140 32144
Child process code domain (correct)
32141 32141 32140
32142 32142 32140
32143 32143 32140
32144 32144 32140
Analysis: why does the child process call the event defined in the parent process?
this requires a careful analysis of the for
loop!
- the first loop, the parent process adds a child process listening event to
Event::$events
, and the child process executes in parallel. For the first child process generated, Event::$events
is empty, so there are no events copied to the parent process.
In the - second loop, the parent process adds a listening child process event to
Event::$events
again, and there is an event Event::$events
for the resulting second child process! An event was copied from the parent process.
In the - third loop, the parent process once again adds listening child process events to
Event::$events
. At this time, for the three generated child processes, Event::$events
has two events! Two events are copied from the parent process.
In the - fourth loop, the parent process again adds events to the
Event::$evnets
. At this time, there are three events in Event::$events
relative to the fourth child process that is generated, and three events are copied from the parent process.
from the above, we know that the child process is actually listening for events copied from the parent process, and if the event is triggered, the parent-child process that listens for the event will actually trigger it. As a result, there is something depressing: the child process intrudes into the realm of the parent process.
< H1 > solution < / H1 >
in the child process, destroy the events copied from the parent process.
for ($i = 0; $i < 4; PP$i)
{
$pid = pcntl_fork();
if ($pid < 0) {
throw new Exception("");
} else if ($pid > 0) {
//
Select::addIo( .... );
// ...
} else {
//
//
Select::clear();
// ....
}
}