同时发送 5000 条推送通知,保持与苹果的连接打开?
Posted
技术标签:
【中文标题】同时发送 5000 条推送通知,保持与苹果的连接打开?【英文标题】:Sending 5000 push notifications at same time, keep the connection to apple open? 【发布时间】:2013-12-24 15:53:27 【问题描述】:现在我正在使用以下代码来发送我的推送通知
function applePush($deviceToken,$sound,$message,$object,$thread = 0)
$passphrase = 'Secret';
$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'secret.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
if (!$fp)
exit("Failed to connect: $err $errstr" . php_EOL);
//Customizable sounds
if ($sound == 0) $sound = 'default';
else $sound = '/' . $sound . '.wav';
// Create the payload body
if ($thread > 0)
$body['aps'] = array(
'alert' => $message,
'sound' => $sound,
'obj' => $object,
't' => $thread,
);
else
$body['aps'] = array(
'alert' => $message,
'sound' => $sound,
'obj' => $object
);
// Encode the payload as JSON
$payload = json_encode($body);
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
// Close the connection to the server
fclose($fp);
我实际上在做的是: 1) 从 SQL 数据库中提取 5000 个(并且不断增长的)设备令牌。 2) 使用 PHP 循环,对于每个设备令牌,我运行上面列出的 applePush 函数
现在这一切正常,每个人都得到了苹果的推动。现在更重要的是,我自己的个人 iphone 是我 SQL 数据库中的第一台设备,我会立即收到推送通知。 但是,我刚买了一部新的 iphone,我现在是数据库中的最后一台设备,我注意到我现在需要将近 30 分钟才能收到通知。我认为这与与苹果建立所有这些连接的物理时间有关,但它到达第 5000 个设备 ID 的时间已经过去了 30 分钟。
这让我读到了,似乎 Apple 实际上建议保持与 APNS 的连接打开,而不是不断打开和关闭连接。
所以我写信来征求大家对此的看法,我做错了吗?如果我是,我该如何修改我的代码以使其符合苹果政策并使其更快/更高效
谢谢!
【问题讨论】:
明确保持连接打开。只需在发送每个请求之间稍作延迟即可。 是的。 TCP 打开/关闭周期是一件非常昂贵的事情,尤其是当数据包有效负载非常小时,例如发送实际数据需要 0.1 秒,打开/关闭连接需要 2 秒,最终您需要等待 166 分钟的 JUST tcp 打开/关闭等待,以及 8 分钟的实际数据传输。 我们在消息和 simes 之间使用usleep(100000);
以正常工作。
稍后您可能想要实现某种消息队列和几个工作脚本,这些脚本同时工作从消息队列中提取 APNS 令牌并将它们发送到 APNS 服务器 - 再次:分批,保持连接打开.. .
@rokjarc 你能在上面的代码中显示一个usleep(10000)
的例子吗? php新手:(
【参考方案1】:
不要打开和关闭连接 5000 次,这是非常昂贵且不可接受的。
该问题与 android 不同,Apple Server 不会将设备令牌数组与播放负载一起使用。
更好的方法是遍历数据库并返回一个数组。
一旦连接打开,这个数组就会被循环使用。
所以你会有这样的东西:
//Apple Push Notifcations
$apn = new Apple_Push_Notifications();
//Get Device tokens into an array
$deviceTokens = array();
$deviceTokens = $apn->GetDeviceTokens();
//Push the notifications
if(count($deviceTokens) > 0)
$apn->applePush($deviceTokens,$sound,$message,$object,$thread);
//In applePush loop through all the tokens and submit
function applePush($deviceTokens,$sound,$message,$object,$thread = 0)
....
// Open a connection to the APNS server
$fp = stream_socket_client(
'ssl://gateway.push.apple.com:2195', $err,
$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
....
....
// Encode the payload as JSON
$payload = json_encode($body);
//Send the Push to each token the close connection
foreach ($deviceTokens as $deviceToken)
// Build the binary notification
$msg = chr(0) . pack('n', 32) . pack('H*', $deviceToken) . pack('n', strlen($payload)) . $payload;
// Send it to the server
$result = fwrite($fp, $msg, strlen($msg));
// Close the connection to the server
fclose($fp);
【讨论】:
【参考方案2】:您应该尽可能长时间地保持连接打开。提高性能的另一种方法是拥有多个线程(每个线程都有自己与 APN 服务器的连接,该服务器保持打开状态)并在它们之间分摊发送推送通知的工作。
在每条消息后关闭连接不仅对性能不利,而且如果 Apple 将其视为 DOS 攻击,还可能会禁止您的 IP。
在多个通知中保持与 APN 的连接处于打开状态; 不要反复打开和关闭连接。 APNs 治疗快速 连接和断开作为拒绝服务攻击。你应该 保持连接打开,除非您知道它将空闲一段时间 延长时间——例如,如果您只向 您的用户每天一次,可以每天使用一个新连接。
【讨论】:
以上是关于同时发送 5000 条推送通知,保持与苹果的连接打开?的主要内容,如果未能解决你的问题,请参考以下文章
如何在不使用php循环的情况下同时向ios设备发送1000条推送通知