【发布时间】:2012-08-28 10:04:55
【问题描述】:
在过去的几天里,我们在使用套接字连接到生产服务器上的 APN 服务器时遇到了 PHP 的一些奇怪行为。
在大多数情况下,有效负载被推送而没有任何错误,并且客户端会收到通知。然而,在某些情况下,我们开始收到 PHP 错误(即使我们收到错误,有时也会推送通知)。当我们开始看到这个错误时,它会持续几个小时然后消失,PHP 继续工作,就像什么都没发生一样。
另一个奇怪的事情是,从 shell 运行相同的 PHP 代码不会产生任何错误。从 web (nginx / php-fpm) 运行它确实......在 shell 和 web 上运行的 PHP 具有相同的配置并共享相同的 php.ini。唯一的区别是 web 是在 php-fpm 上运行的。
此外,相同的代码 + 证书在我们的暂存服务器上运行,没有任何错误。生产服务器是暂存服务器的副本,因此每个配置都是相同的。
我们能够找到一些可能导致此错误的答案,包括来自 stackoverflow.com 的答案,但我们无法找到解决方案或解决它。
发送到 Apple 服务器的通知是逐个发送的,而不是捆绑发送的。但是我们并没有建立太多的联系(可能每天有一千个)。没有排队系统。
总之
- 我们有时会在发送通知时收到 PHP 错误,但并非总是如此。
- 通过相同的 PHP 从 shell 发送通知不会产生任何错误
- 从暂存服务器发送通知不会产生任何错误
我们试过这些
- 重新创建证书和密钥
- 重新创建 PEM 文件
- 将 ssl:// 更改为 sslv3://
- 使用 stream_socket_client
- 使用 fsockopen
- 更改/删除证书密码
错误是:
2012/08/28 12:18:09 [error] 4282#0: *225858 FastCGI sent in stderr:
"PHP message: PHP Warning: fwrite() [<a href='function.fwrite'>function.fwrite</a>]:
SSL operation failed with code 1. OpenSSL Error messages:
error:1409F07F:SSL routines:func(159):reason(127) in
/usr/local/nginx/html/play/classes/PushNotification.php on line 283"
while reading response header from upstream, client: 94.---.---.---,
server: play.--------.com, request: "POST /game_request_random.php HTTP/1.1",
upstream: "fastcgi://unix:/var/run/phpfpm.sock:",
host: "play.--------.com", referrer: "http://--------.com/"
从php连接和发送payload的代码实际上是一个类的一部分,这部分是什么使连接和发送payload:
private function ConnectAndSend ( $msg = false ) {
$ctx = stream_context_create();
stream_context_set_option( $ctx, 'ssl', 'local_cert', $this->certificate );
stream_context_set_option( $ctx, 'ssl', 'passphrase', $this->certificatepass );
// Open a connection to the APNS server
$fp = stream_socket_client( APN_SERVER, $err, $errstr, 60, STREAM_CLIENT_CONNECT | STREAM_CLIENT_PERSISTENT, $ctx );
if ( !$fp ) {
errorlog( "Push notification error : $err $errstr" );
$this->error = "$err $errstr";
return;
}
// Build the notification
if ( !$msg ) {
$msg = chr( 0 ) . pack( 'n', 32 ) . pack( 'H*', $this->devicetoken ) . pack( 'n', strlen( $this->payload ) ) . $this->payload;
}
// Send it to the server
if ( !($result = fwrite( $fp, $msg, strlen( $msg ) )) ) {
// Could not send
$this->error = 'Notification could not be send';
errorlog( "Push notification error : {$this->error}" );
} else {
// Notification sent
$this->error = false;
errorlog( "Push notification sent" );
}
fclose($fp);
// Reset the content
$this->devicetoken = false;
$this->message = false;
$this->command = false;
$this->badge = 0;
$this->payload = false;
$this->sound = false;
}
- stream_socket_connection 是出现在错误消息中的第 283 行
- 我们没有使用沙盒 (sslv3://gateway.push.apple.com:2195)
- PHP 版本为 5.3.15
这是一个我们不知道的 PHP 或 OpenSSL 错误吗?任何想法什么和在哪里检查? Apple 是否有可以检查 APN 网络当前运行状况的网站?
非常感谢任何帮助... 谢谢
【问题讨论】:
-
另外:我们增加了linux内核对socket连接的限制,并且发现php.ini socket连接超时设置为600秒(不是60秒)作为默认值。在这些更改之后,我们没有看到任何错误(目前)。
-
您能分享一下您的 fsockopen 实现吗?我尝试将此功能用于我的通知。
-
检查 php.ini 的套接字限制,尤其是超时。保持在最低限度。我们的问题是 php-fpm 在释放套接字时遇到问题。如果您使用 linux 作为服务器,请尝试更改有关套接字(tcp/ip 堆栈)的内核限制。谷歌“改变 linux 内核限制”,一些 IBM 网站有一些关于这个主题的好帖子。但是,这是非常危险的,所以要小心。这也解决了我们的问题(在编辑 php.ini 之前),过去 8 个月我们没有看到任何错误。
-
@emrahgunduz 你有没有解决这个问题?我今天用 APN 遇到了同样的事情。到目前为止,它运行良好。谢谢。
-
@tamak 首先,检查以确保您没有忘记在代码结束之前关闭套接字。如果您使用的是 linux,请在后端增加打开文件限制(检查内核限制)。检查您的日志并确保您没有收到来自 php-fpm 的 FD_SETSIZE 错误(如果是这种情况,您必须在增加内核 FD_SETSIZE 限制后重新编译 php,搜索 --enable-fd-setsize)。如果你在 Windows 上,对不起,我不知道。
标签: php ios apple-push-notifications