发送voip推送通知后是否应关闭与APN的连接?

时间:2018-03-16 19:37:16

标签: ios swift apple-push-notifications

我使用simplepush.php脚本将voip推送从用户发送给用户。 我的应用程序可能会根据获取的用户数量来完成许多推送请求。我发现的simplepush.php的每个例子似乎都在最后明确地关闭了连接 - 这是我的脚本(见最后一行):

$ctx = stream_context_create();
stream_context_set_option($ctx, 'ssl', 'local_cert', 'voip.pem');
stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);

// Open a connection to the APNS server
$fp = stream_socket_client($apnsUrl, $err,
    $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);

if (!$fp)
    exit("Failed to connect: $err $errstr" . PHP_EOL);

echo 'Connected to APNS' . PHP_EOL;

// Create the payload body
$body['aps'] = array(
    'alert' => $message,
    'sound' => 'default'
    );

$body['info'] = array(
  'roomname' => $roomName,
  'uuid' => $uuid
  );

// 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));

if (!$result)
    echo 'Message not delivered' . PHP_EOL;
else
    echo 'Message successfully delivered' . PHP_EOL;

// Close the connection to the server
fclose($fp);

请注意:我使用旧版APNs二进制接口发送通知而不是HTTP / 2请求,因为所有simplepush脚本都使用它。我不熟悉PHP,但似乎脚本在每次调用结束时关闭连接:fclose($fp);

但根据Apple的说法我应该保持连接打开:

  

管理连接的最佳实践   通过多个通知保持与APN的连接;不要反复打开和关闭连接。 APN将快速连接和断开视为拒绝服务攻击。   https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW6

但是由于我使用的是传统二进制接口,我是否应该在每次通话后关闭连接?或者我在这里误解fclose($fp);功能?使用这个二进制文件时处理连接的适当方式的任何清晰度都将非常感激!

1 个答案:

答案 0 :(得分:3)

说明

据我所知,不关闭每个通知的连接的建议来自批量通知传送的区域,其中许多用户被传递相同的通知。

除了可能被解释为攻击之外,关闭和重新开启的效率非常低,并且会导致巨大的交付延迟。只是在流上写二进制消息比打开和关闭每个通知要快得多。见这个例子:

// Open a connection to the apns server (this code is the same as a few lines below, so if changed here, also change there)
$stream_context = stream_context_create();
stream_context_set_option($stream_context, 'ssl', 'local_cert', 'voip.pem');
stream_context_set_option($stream_context, 'ssl', 'passphrase', 'secret_pass');
$apns = stream_socket_client($url, $err, $errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $stream_context);

// Return if connection is impossible
if (!$apns) { return; }

// Create payload body
$body['aps'] = array(
    'alert' => $title,
    'badge' => 1
);

// Encode the payload as json
$payload = json_encode($body);

// Iterate through token array
foreach($tokens as $token) {    
    $user_id = 2 // Random id ;)

    // Build binary notification
    $msg = pack("C", 1);
    $msg .= pack("N", $user_id);
    $msg .= pack("N", $notification_expiration_date);
    $msg .= pack("n", 32);
    $msg .= pack('H*', $token);
    $msg .= pack("n", strlen($payload));
    $msg .= $payload;

    // Send to the server
    $fwrite_result = fwrite($apns, $msg, strlen($msg));
}

fclose($apns);

了解它如何打开一个连接,为数组中的每个标记写入,然后关闭,而不是每次都打开,写入和关闭。

以批量推送应用程序为例,现在是您的设计决定是否应保留连接。如果您每小时发送一次通知,我认为打开和关闭每个通知都是合适的。但是,如果每分钟有多个通知的吞吐量,则需要保持连接打开。

建议

您可以采取的一种方法是在完成现有队列后查找要传递的任何新通知。如果没有,你可以等待几分钟,然后再次检查并关闭连接,如果还没有新的,如果有的话,保持打开并使用相同的连接发送新的通知。

这符合Apple的建议:

  

您应该保持连接打开,除非您知道它将在一段时间内处于空闲状态 - 例如,如果您每天只向用户发送一次通知,则可以接受每天使用新连接的做法。

警告

使用单个连接时需要考虑的一个重要事项是错误处理:无效的令牌(生产/沙箱模式混淆)可能会导致连接关闭,而您没有注意到,但还有其他帖子进一步讨论。