2012-01-09 20 views
5

He implementado c2dm y funciona bien que el dispositivo reciba el mensaje y todo. Sin embargo, hay un problema para el que no puedo encontrar una solución.Android, envía mensajes a 1000 dispositivos rápidamente

Cuando ocurre un evento determinado, deseo enviar el mismo mensaje a unos miles de dispositivos rápidamente, preferiblemente en un minuto. Sé que no hay certeza de que el mensaje llegue a entregarse alguna vez y que Google puede retrasar el mensaje debido a diferentes circunstancias.

Mi implementación para iOS es casi la misma excepto, por supuesto, la parte de envío. Eso demora alrededor de 5 segundos para 15000 mensajes. Para 5000 mensajes a Android, toma más de una hora, que es demasiado larga.

¿Alguien sabe una manera de acelerar esto? ¿O Google detiene este tipo de impulso masivo para detener el correo no deseado?

La parte C2DM del código está debajo. Esto está en PHP pero no tengo problemas para leer la mayoría de los otros lenguajes de programación. Utilizo un script para connect() una vez y luego repito todos los tokens y uso sendMessage() para enviar cada mensaje. Después de enviar todos los mensajes, se desconecta().

<?php 
class C2DMclient 
{ 
    private $authKey = NULL; 
    private $ch = NULL; 

    function connect() { 
     $post_params = array(
      'Email'  => 'C2DM_USER', 
      'Passwd'  => 'C2DM_PWD', 
      'accountType' => 'HOSTED_OR_GOOGLE', 
      'source'  => 'appname', 
      'service'  => 'ac2dm', 
     ); 
     $first = true; 
     $data_msg = ''; 

     foreach($post_params as $key => $value) { 
      if($first) 
       $first = false; 
      else 
       $data_msg .= '&'; 

      $data_msg .= urlencode($key).'='.urlencode($value); 
     } 

     $x = curl_init('C2DM_CLIENTLOGIN'); 
     curl_setopt($x, CURLOPT_HEADER, true); 
     curl_setopt($x, CURLOPT_POST, true); 
     curl_setopt($x, CURLOPT_POSTFIELDS, $data_msg); 
     curl_setopt($x, CURLOPT_RETURNTRANSFER, true); 
     $response = curl_exec($x); 
     curl_close($x); 

     $pos = strpos($response, 'Auth='); 
     $this->authKey = trim(substr($response, 5 + $pos)); 
     $this->ch = curl_init(); 
     curl_setopt($this->ch, CURLOPT_URL, 'C2DM_SERVER'); 
    } 

    function disconnect() { 
     curl_close($this->ch); 
     $this->authKey = NULL; 
    } 

    function sendMessage($deviceToken, $message) { 
     $data = array(
      'registration_id' => $deviceToken, 
      'collapse_key' => 'ck_type', 
      'data.type'  => 'TYPE', 
      'data.message' => $message, 
      'data.title'  => 'Title' 
     ); 
     $headers = array('Authorization: GoogleLogin auth='.$this->authKey); 

     if($headers) 
      curl_setopt($this->ch, CURLOPT_HTTPHEADER, $headers); 

     curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0); 
     curl_setopt($this->ch, CURLOPT_POST, true); 
     curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, true); 
     curl_setopt($this->ch, CURLOPT_POSTFIELDS, $data); 

     $messagedata = curl_exec($this->ch); 
      return TRUE; 
    } 
} 
?> 

EDIT: Nueva solución se basa en curl_multi_exec.

Los controladores curl se recopilan mientras se repiten los resultados de la consulta de la base de datos. Después de reunir unos cientos de controladores de curl, se invocan sendMessages ($ chs) para enviar todos esos mensajes. Por el momento, recopilo 700 mensajes antes de enviarlos y parece que tengo una buena tasa de entrega y lo suficientemente rápido, ~ 10 segundos para enviar 5000 mensajes. Un número más alto parece afectar la tasa de entrega.

<?php 
class C2DMclient 
{ 
    private $authKey = NULL; 
    private $ch = NULL; 

    function connect() { 
     $post_params = array(
      'Email'  => 'C2DM_USER', 
      'Passwd'  => 'C2DM_PWD', 
      'accountType' => 'HOSTED_OR_GOOGLE', 
      'source'  => 'appname', 
      'service'  => 'ac2dm', 
     ); 
     $first = true; 
     $data_msg = ''; 

     foreach($post_params as $key => $value) { 
      if($first) 
       $first = false; 
      else 
       $data_msg .= '&'; 

      $data_msg .= urlencode($key).'='.urlencode($value); 
     } 

     $x = curl_init('C2DM_CLIENTLOGIN'); 
     curl_setopt($x, CURLOPT_HEADER, true); 
     curl_setopt($x, CURLOPT_POST, true); 
     curl_setopt($x, CURLOPT_POSTFIELDS, $data_msg); 
     curl_setopt($x, CURLOPT_RETURNTRANSFER, true); 
     $response = curl_exec($x); 
     curl_close($x); 

     $pos = strpos($response, 'Auth='); 
     $this->authKey = trim(substr($response, 5 + $pos)); 
    } 

    function getMessageCurlHandle($deviceToken, $message) { 
     $ch = curl_init(); 
     curl_setopt($ch, CURLOPT_URL, 'C2DM_SERVER'); 
     $data = array(
      'registration_id' => $deviceToken, 
      'collapse_key' => 'ck_type', 
      'data.type'  => 'TYPE', 
      'data.message' => $message, 
      'data.title'  => 'Title' 
     ); 
     $headers = array('Authorization: GoogleLogin auth='.$this->authKey); 

     if($headers) 
      curl_setopt($ch, CURLOPT_HTTPHEADER, $headers); 
     curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0); 
     curl_setopt($ch, CURLOPT_POST, true); 
     curl_setopt($ch, CURLOPT_POSTFIELDS, $data); 
     return $ch; 
    } 

    function sendMessages($chs) { 
     $mh = curl_multi_init(); 
     foreach($chs as $ch) { 
      curl_multi_add_handle($mh, $ch); 
     } 
     $active = null; 
     do { 
      $mrc = curl_multi_exec($mh, $active); 
     } while($mrc == CURLM_CALL_MULTI_PERFORM); 

     while($active && $mrc == CURLM_OK) { 
      if(curl_multi_select($mh) != -1) { 
       do { 
        $mrc = curl_multi_exec($mh, $active); 
       } while($mrc == CURLM_CALL_MULTI_PERFORM); 
      } 
     } 
     curl_multi_close($mh); 
    } 
} 
?> 

Respuesta

4

[Actualización] C2DM es ahora deprecated. Es el sucesor Google Cloud Messaging (GCM) apoya multiple receivers también conocido como el envío de lotes:

{ "data": { 
    "score": "5x1", 
    "time": "15:10" 
    }, 
    "registration_ids": ["4", "8", "15", "16", "23", "42"] 
} 

[/ Actualización]

C2DM doesn't support el envío de lotes aún.

Sin embargo, podría enviar varias solicitudes POST al servidor C2DM al mismo tiempo, desafortunadamente PHP no tiene soporte para multi-threading.

Eche un vistazo a curl_multi_exec que le da la posibilidad de hacer varias solicitudes de CURL al mismo tiempo.

+0

sé que C2DM no admite el envío de lotes y por lo tanto hago un puesto por cada mensaje. Por alguna razón, este proceso lleva mucho tiempo. Echaré un vistazo a curl_multi_exec. Tal vez es curl en sí que lleva mucho tiempo. Voy a cronometrar un poco más y regresaré si encuentro algo interesante. – Daniel

+0

curl_multi_exec parecía ser la solución. Después de probarlo durante unos días, el tiempo para enviar 5000 mensajes pasó de más de una hora a una cuestión de segundos. Sin embargo, es bastante aleatorio si el mensaje alguna vez recibe los mensajes. Algunos parecen perderse en el camino. Supongo que 2000 mensajes a la vez es para muchos e intentaré modificar esto para obtener un rendimiento óptimo frente a la velocidad. Actualizaré la publicación original cuando tenga el tiempo. – Daniel

0

También investigaría Firebase, he estado jugando con ellos un poco últimamente, y parece muy rápido. Tienen API para una amplia gama de marcos. Su objetivo es impulsar los cambios en los conjuntos de datos (los mensajes son un ejemplo perfecto) muy rápidamente, de modo que cuando sucede un cambio envían un mensaje de notificación a todos los usuarios conectados.

https://www.firebase.com/

Cuestiones relacionadas