我正在尝试使用PHP中的SSL / TLS连接发送大量数据。如果数据块不是很大或者我不使用TLS,但是我需要(接近2MiB),fwrite
函数显示警告:
警告:fwrite():SSL操作失败,代码为1. OpenSSL错误消息:错误:1409F07F:SSL例程:SSL3_WRITE_PENDING:错误的写入重试
我用来连接客户的相关代码:
$cntxt = stream_context_create(array('ssl' => array('local_cert' => 'certificate.pem')));
$server = stream_socket_server('tls://127.0.0.1:8080', $errno, $errstr, STREAM_SERVER_BIND|STREAM_SERVER_LISTEN, $cntxt);
// Wait for client connection //
$client = stream_socket_accept($server);
// Use non-blocking socket to allow answering many clients at a time
stream_set_blocking($client, 0);
$clients[] = $client;
发送数据时,它会附加到缓冲区,并且有时会为每个客户端和链接缓冲区调用此函数:
function trySend($client, &$buffer) {
if (strlen($buffer)) {
$len = fwrite($client, $buffer);
$buffer = substr($buffer, $len);
}
}
正如我所说,我的代码适用于少量数据或普通(非TLS)连接。我搜索了这个错误并找到http://www.openssl.org/docs/ssl/SSL_write.html:
当写入长度为num的buf的完整内容时,SSL_write()将仅成功返回。可以使用SSL_CTX_set_mode(3)的SSL_MODE_ENABLE_PARTIAL_WRITE选项更改此默认行为。设置此标志后,当成功完成部分写入时,SSL_write()也将成功返回。在这种情况下,SSL_write()操作被视为已完成。发送字节并且必须启动带有新缓冲区(已删除已发送字节)的新SSL_write()操作。使用消息块的大小执行部分写入,对于SSLv3 / TLSv1,该大小为16kB。
但我怎么能用PHP做到这一点?
任何帮助表示赞赏:)
答案 0 :(得分:1)
我发现我可以通过将传递给fwrite()的字符串长度限制为8192来解决这个问题,这会阻止fwrite()警告。
因此,对于您示例中的代码,我会尝试将substr()调用更改为:
$buffer = substr($buffer, $len, 8192);
答案 1 :(得分:-2)
解决方案是:
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
try {
$result = fwrite($fp, $msg, strlen($msg));
}
catch (Exception $ex) {
sleep(1); //sleep for 5 seconds
$result = fwrite($fp, $msg, strlen($msg));
}