title: What language to use for Push Notification Server maintaining socket stream connection to Apple Push Notification Server
body: <p>I am implementing a Push Notification server for our iPhone application.</p>
  
  <p>I am using Symfony web framework to build my backend system for my iPhone application.</p>
  
  <p>The way I have built the push notification server is:</p>
  
  <p>1) Make a socket stream connection to Apple's PNS.</p>
  
  <p>2) Start an infinite while loop</p>
  
  <p>3) Inside the while loop, look for any new notifications in the SQL database</p>
  
  <p>4) If there are new push notification entities in my SQL database, get them all and send them out</p>
  
  <p>Below is my PHP code:</p>
  
  <pre><code>// ----------------------------------------------------------
  // Opens a connection to Apple's Push Notification server
  // ----------------------------------------------------------
  public function pnsConnect()
  {
      // push notification pem certificate file
      //$this-&gt;apnscert_dev = $this-&gt;container-&gt;getParameter('apnscert_dev');
      //$this-&gt;apnshost_dev = $this-&gt;container-&gt;getParameter('apnshost_dev');
      $this-&gt;apnscert_dev = 'cert_and_key_dev.pem';
      $this-&gt;apnshost_dev = 'gateway.sandbox.push.apple.com';
      $this-&gt;apnsport = 2195; //$this-&gt;container-&gt;getParameter('apnsport');
  
      $pempath_dev = __DIR__."/../Resources/config/".$this-&gt;apnscert_dev;
  
      echo 'pem path = '.$pempath_dev.'&lt;br /&gt;';
  
      $streamContext = stream_context_create();
  
      stream_context_set_option($streamContext, 'ssl', 'local_cert', $pempath_dev);
  
      // push notification server connection object
      $this-&gt;apns = stream_socket_client('ssl://' . $this-&gt;apnshost_dev . ':' . $this-&gt;apnsport, $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);
      error_log(date('Y-m-d H:i:s')." - Successfully connected to APNS", 3, 'PushLog.log'); // log for successful connection to help with debugging
  }
  
  
  // ---------------------------------------------------------
  // Sends a push notification to multiple targeted tokens
  // i.e. a group of users
  //
  // pnsSendToTokenGroup() only sends to a group, not a list
  // of tokens specifically selected
  // ---------------------------------------------------------    
  public function pnsSendToMultiple($paramArrTokens, $paramMessage)
  {
      if(!$paramMessage || !$paramArrTokens)
      {
          return new Response('Missing input parameters');
      }
  
      $badge = 1;
      $sound = 'default';
      $development = true;
  
      $payload = array();
      $payload['aps'] = array('alert' =&gt; $paramMessage, 'badge' =&gt; intval($badge), 'sound' =&gt; $sound);
      $payload = json_encode($payload);
  
      //echo 'message = '.$paramMessage.'&lt;br /&gt;';
  
      //echo '&lt;br /&gt;Received '.count($paramArrTokens).' tokens&lt;br /&gt;';
  
      foreach($paramArrTokens as $paramToken)
      {
          //echo 'current token = '.$paramToken.'&lt;br /&gt;';
  
          $apns_message = chr(0).chr(0).chr(32).pack('H*', str_replace(' ', '', $paramToken)).chr(0).chr(strlen($payload)).$payload;
          fwrite($this-&gt;apns, $apns_message);
  
          $apns_message = null;
          //$paramToken = null;
      }
  
      $badge = null;
      $sound = null;
      $development = null;
      $payload = null;
  
      //$paramArrTokens = null;
      //$paramMessage = null;
  }
  
  
  // ---------------------------------------------------------
  // Keeps this PNS server alive to maintain the connection
  // to Apple's PNS server. This process will continually
  // check the database for any new notification and push
  // the notificaiton to who ever we need to.
  // ---------------------------------------------------------    
  public function pnsKeepAlive()
  {
      // prevents time out
      ini_set('max_input_time', 0);
      ini_set('max_execution_time', 0);
  
      $this-&gt;pnsDisconnect();
      $this-&gt;pnsConnect();
  
      // circular reference collector
      gc_enable();
  
      // start infinite loop to keep monitoring for new notifications
      while(true)
      {
          echo 'checking database for new notifications ...&lt;br /&gt;';
  
          set_time_limit(0);
  
          gc_collect_cycles();
  
          $today = new DateTime('today');
          $now = new DateTime();
  
          $query = $this-&gt;em-&gt;createQuery('SELECT n FROM MyAppWebServiceBundle:Notification n WHERE n.sent = :paramSent and n.notificationdate &gt;= :paramDate and n.notificationdate &lt;= :paramNow')
              -&gt;setParameter('paramSent', false)
              -&gt;setParameter('paramDate', $today)
              -&gt;setParameter('paramNow', $now);
  
          $notifications = $query-&gt;getResult();
  
          $today = null;
          $now = null;
  
          //echo 'number of unsent notifications found for today = '.count($notifications).'&lt;br /&gt;';
  
          // for each notification, combine all tokens into a single array
          // to be looped through and sent into notification processing queue
          foreach($notifications as $notification)
          {
              $this-&gt;pushNotification($notification);
          }
  
          $this-&gt;em-&gt;detach($query);
  
          $notifications = null;
          $query = null;
      }
  
      $this-&gt;pnsDisconnect();
  }
  
  
  
  
  // ---------------------------------------------------------    
  // Finds all tokens attached to Notification
  // and construct an array of all unique tokens to be
  // sent out to all receivers of the notification
  // ---------------------------------------------------------    
  public function pushNotification($notification)
  {
      // initialise an empty array
      $arrAllTokens = array();
  
      // add all raw tokens to final array first
      foreach($notification-&gt;getTokens() as $token)
      {
          // only add active tokens
          if($token-&gt;getActive() == true)
          {
              $arrAllTokens[] = $token-&gt;getToken();
          }
      }
  
      // for each token group add all 
      // tokens in each group to final array
      foreach($notification-&gt;getTokenGroups() as $tokenGroup)
      {
          foreach($tokenGroup-&gt;getTokens() as $token)
          {
              // only add active tokens
              if($token-&gt;getActive() == true)
              {
                  $arrAllTokens[] = $token-&gt;getToken();
              }
          }
      }
  
      $arrAllTokens = array_unique($arrAllTokens);
  
      $this-&gt;pnsSendToMultiple($arrAllTokens, $notification-&gt;getMessage());
  
      $notification-&gt;setSent(true);
      $this-&gt;em-&gt;flush();
      $this-&gt;em-&gt;detach($notification);
  
      $arrTokens = null;
      $arrAllTokens = null;
      $notification = null;
  }
  </code></pre>
  
  <p>Apple have stated that a Push Provider should maintain connection to Apple's Push Server and not frequently disconnection and reconnect, otherwise they treat it as a denial of service attack and block us.</p>
  
  <p>That is why I have an infinite while loop so the script doesn't end to allow me to maintain the constant connection to Apple's push notification socket stream.</p>
  
  <p>At the moment, my push notification server works on my local machine (my pnsKeepAlive() infinite while loop goes on forever) but when I deploy my code to the production server, my pnsKeepAlive() (see above code) does not go on forever.</p>
  
  <p>My production server is a shared hosting on Linode. It is a LAMP server running Apache and Debian.</p>
  
  <p>I have heard PHP isn't designed to be doing these kind of jobs.</p>
  
  <p>So my questions whether there are other language that is designed for these kind of thing (maintaining a persistent connection for a push notification server).</p>
  
  <p>I have looked into Gearman but was also told by others Gearman isn't really what I need.</p>