1
0
Fork 0

Fork a child process for every TCP connection

pull/183/head
Felix Becker 2016-11-25 11:51:20 +01:00
parent 22ae5e509d
commit 9a42472d71
2 changed files with 51 additions and 17 deletions

View File

@ -151,8 +151,8 @@ Example:
#### `--tcp-server=host:port` (optional) #### `--tcp-server=host:port` (optional)
Causes the server to use a tcp connection for communicating with the language client instead of using STDIN/STDOUT. Causes the server to use a tcp connection for communicating with the language client instead of using STDIN/STDOUT.
The server will listen on the given address for a connection. The server will listen on the given address for a connection.
It will only accept one connection and the connection cannot be reestablished once closed, spawn a new process instead. If PCNTL is available, will fork a child process for every connection.
Strongly recommended on Windows because of blocking STDIO. If not, will only accept one connection and the connection cannot be reestablished once closed, spawn a new process instead.
Example: Example:

View File

@ -31,31 +31,65 @@ set_exception_handler(function (\Throwable $e) {
@cli_set_process_title('PHP Language Server'); @cli_set_process_title('PHP Language Server');
if (!empty($options['tcp'])) { if (!empty($options['tcp'])) {
// Connect to a TCP server
$address = $options['tcp']; $address = $options['tcp'];
$socket = stream_socket_client('tcp://' . $address, $errno, $errstr); $socket = stream_socket_client('tcp://' . $address, $errno, $errstr);
if ($socket === false) { if ($socket === false) {
fwrite(STDERR, "Could not connect to language client. Error $errno\n"); fwrite(STDERR, "Could not connect to language client. Error $errno\n$errstr");
fwrite(STDERR, "$errstr\n");
exit(1); exit(1);
} }
$inputStream = $outputStream = $socket; stream_set_blocking($socket, false);
$ls = new LanguageServer(
new ProtocolStreamReader($socket),
new ProtocolStreamWriter($socket)
);
Loop\run();
} else if (!empty($options['tcp-server'])) { } else if (!empty($options['tcp-server'])) {
// Run a TCP Server
$address = $options['tcp-server']; $address = $options['tcp-server'];
$tcpServer = stream_socket_server('tcp://' . $address, $errno, $errstr); $tcpServer = stream_socket_server('tcp://' . $address, $errno, $errstr);
if ($socket === false) { if ($socket === false) {
fwrite(STDERR, "Could not listen on $address. Error $errno\n"); fwrite(STDERR, "Could not listen on $address. Error $errno\n$errstr");
fwrite(STDERR, "$errstr\n");
exit(1); exit(1);
} }
$socket = stream_socket_accept($tcpServer); if (!extension_loaded('pcntl')) {
$inputStream = $outputStream = $socket; fwrite(STDERR, 'PCNTL is not available. Only a single connection will be accepted');
}
while ($socket = stream_socket_accept($tcpServer)) {
stream_set_blocking($socket, false);
if (extension_loaded('pcntl')) {
// If PCNTL is available, fork a child process for the connection
// An exit notification will only terminate the child process
$pid = pcntl_fork();
if ($pid === -1) {
fwrite(STDERR, 'Could not fork');
exit(1);
} else if ($pid === 0) {
// Child process
$ls = new LanguageServer(
new ProtocolStreamReader($socket),
new ProtocolStreamWriter($socket)
);
Loop\run();
// Just for safety
exit(0);
}
} else {
// If PCNTL is not available, we only accept one connection.
// An exit notification will terminate the server
$ls = new LanguageServer(
new ProtocolStreamReader($socket),
new ProtocolStreamWriter($socket)
);
Loop\run();
}
}
} else { } else {
$inputStream = STDIN; // Use STDIO
$outputStream = STDOUT; stream_set_blocking(STDIN, false);
$ls = new LanguageServer(
new ProtocolStreamReader(STDIN),
new ProtocolStreamWriter(STDOUT)
);
Loop\run();
} }
stream_set_blocking($inputStream, false);
$server = new LanguageServer(new ProtocolStreamReader($inputStream), new ProtocolStreamWriter($outputStream));
Loop\run();