我正在开发一个 SSL websocket 服务器,PHP 8.2。
我可以毫无问题地接受 SSL 连接。
问题是:
连接 A、B、C、D 均被接受。
当连接 C 关闭时(是客户端而不是服务器断开连接),连接 A 和 B 会意外关闭(但 D 不会)。
流套接字 A 或 B 上的“fread”将引发此警告: fread(): SSL 操作失败,代码为 1。OpenSSL 错误消息: 错误:140943FC:SSL 例程:ssl3_read_bytes:sslv3 警报坏记录 mac in....
在套接字 D 上读取仍然可以。
只有 SSL 连接才会出现这种情况,未加密的连接不会出现这种情况。
事实上,在关闭套接字之前打开的所有套接字也都已关闭。
我的代码示例:
$transport = 'tlsv1.3';
$ssl = ['ssl' => [
'local_cert' => $sslCert,
'local_pk' => $sslKey,
'disable_compression' => true,
'verify_peer' => false,
'allow_self_signed' => true,
'ssltransport' => $transport,
] ];
$context = stream_context_create($ssl);
$socketS = stream_socket_server(
'ssl://0.0.0.0:'.$wssPort,
$errno,
$errstr,
STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,
$context
);
....
do {
$tCpy = array($socketS);
$retSocket=stream_select($tCpy, $null, $null, 20, 0);
if ($retSocket>0 ) {
// New conection
stream_set_blocking($socketS, true);
$cliSocket = stream_socket_accept($socketS,5,$ip);
...
$pid = pcntl_fork();
if ($pid>0) {
// OK
echo("Fork ok");
continue;
} else if ($pid < 0) {
echo("Error fork");
continue;
} else break;
}
} while(true);
// Do something with newly connected client...
有什么想法吗?谢谢!
嗯,看来我发现了这个问题,所以我发布回复,如果它可以帮助其他人:
关键是加密必须在fork语句之后开始。
所以,这是代码:
$transport = 'tlsv1.3';
$ssl = ['ssl' => [
'local_cert' => $sslCert,
'local_pk' => $sslKey,
'disable_compression' => true,
'verify_peer' => false,
'allow_self_signed' => true,
'ssltransport' => $transport,
] ];
$context = stream_context_create($ssl);
// Change from ssl:// to tcp://
$socketS = stream_socket_server(
'tcp://0.0.0.0:'.$wssPort,
$errno,
$errstr,
STREAM_SERVER_BIND|STREAM_SERVER_LISTEN,
$context
);
....
do {
$tCpy = array($socketS);
$retSocket=stream_select($tCpy, $null, $null, 20, 0);
if ($retSocket>0 ) {
// New conection
stream_set_blocking($socketS, true);
$cliSocket = stream_socket_accept($socketS,5,$ip);
...
$pid = pcntl_fork();
if ($pid>0) {
// OK
echo("Fork ok");
continue;
} else if ($pid < 0) {
echo("Error fork");
continue;
} else break;
}
} while(true);
// Do something with newly connected client...
// Here we start the crypto using the context
stream_socket_enable_crypto($cliSocket,true,STREAM_CRYPTO_METHOD_TLS_SERVER);