Я пытаюсь отправить огромное количество данных, используя SSL / TLS-соединение в PHP. Он работает очень хорошо, если блок данных не очень большой или если я не использую 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 :
SSL_write () вернется с успехом, когда будет записано полное содержимое buf длины num. Это поведение по умолчанию можно изменить с помощью опции SSL_MODE_ENABLE_PARTIAL_WRITE для SSL_CTX_set_mode (3). Когда этот флаг установлен, SSL_write () также вернется с успехом, когда частичная запись была успешно завершена. В этом случае операция SSL_write () считается завершенной. Байты отправляются и запускается новая операция SSL_write () с новым буфером (с удаленными уже удаленными байтами). Частичная запись выполняется с размером блока сообщений, который составляет 16 КБ для SSLv3 / TLSv1.
Но как я могу это сделать в PHP?
Любая помощь оценили 🙂
Я нашел, что могу обойти эту проблему, ограничив длину строки, переданной в fwrite (), на 8192, что предотвращает предупреждение fwrite ().
Поэтому для кода в вашем примере я бы попытался изменить вызов substr () на:
$buffer = substr($buffer, $len, 8192);
Решение:
$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)); }