<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>BodegaWeb &#187; Flash</title>
	<atom:link href="http://bodegaweb.com/tag/flash/feed" rel="self" type="application/rss+xml" />
	<link>http://bodegaweb.com</link>
	<description>De todo un poco en internet</description>
	<lastBuildDate>Fri, 30 Apr 2010 04:37:20 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Servidor de Sockets en PHP</title>
		<link>http://bodegaweb.com/servidor-de-sockets-en-php.html</link>
		<comments>http://bodegaweb.com/servidor-de-sockets-en-php.html#comments</comments>
		<pubDate>Mon, 30 Mar 2009 07:51:48 +0000</pubDate>
		<dc:creator>ramzax200</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Scripts]]></category>
		<category><![CDATA[Software]]></category>
		<category><![CDATA[Flash]]></category>
		<category><![CDATA[Raymond Fain]]></category>
		<category><![CDATA[Servidor]]></category>
		<category><![CDATA[Sockets]]></category>

		<guid isPermaLink="false">http://bodegaweb.com/?p=86</guid>
		<description><![CDATA[Un servidor de sockets es un servidor que posibilita la comunicacion entre multiples computadoras por medio de sockets, consume mucho menos recursos y bandwitdh que la comunicacion http, y es ideal para los juegos Multijugadores y Online hechos con Action Script de Flash o cualquier otro programa o lenguaje.
En esta entrada te explicaremos de manera [...]]]></description>
			<content:encoded><![CDATA[<div id="attachment_124" class="wp-caption alignright" style="width: 160px"><a href="http://bodegaweb.com/wp-content/uploads/2009/03/5345php.jpg"><img class="size-thumbnail wp-image-124" title="Servidor de Sockets en PHP" src="http://bodegaweb.com/wp-content/uploads/2009/03/5345php-150x106.jpg" alt="Servidor de Sockets en PHP" width="150" height="106" /></a><p class="wp-caption-text"> </p></div>
<p>Un servidor de sockets es un servidor que posibilita la comunicacion entre multiples computadoras por medio de sockets, consume mucho menos recursos y bandwitdh que la comunicacion http, y es <strong>ideal </strong>para los juegos <strong>Multijugadores </strong>y <strong>Online </strong>hechos con Action Script de Flash o cualquier otro programa o lenguaje.</p>
<p>En esta entrada te explicaremos de manera rapida como Crear tu propio servidor de Sockets en PHP.</p>
<p><span id="more-86"></span></p>
<p>Fuente en Ingles: http://djz.hu/2007/07/26/php-socket-server-chat-gateway-for-flash-clients/</p>
<p>Primero que nada, no pienso escribir un manual paso a paso de &#8220;COMO CREAR UN SOCKET SERVER CON PHP PARA FLASH O JUEGOS MULTIJUGADORES EN 10 MINUTOS&#8221; o algo asi.<br />
Lo que haremos sera solo explicar el funcionamiento basico del servidor de sockets con php y comunicarlo con flash en un puerto determinado.</p>
<p>Presentare ademas del codigo del servidor de sockets, un sencillo archivo en Flash, capaz de demostrar el funcionamiento de Flash con un Servidor de Sockets en php.</p>
<p>La idea fundamental y la base del sistema la hemos extraido de aqui : <a href="http://www.kirupa.com/developer/flash8/php5sockets_flash8.htm" target="_blank">kirupa.com &#8211; PHP 5 Sockets with Flash 8</a></p>
<p>Para empezar necesitamos de preferencia un servidor dedicado propio, o un servidor virtual al cual podamos tener acceso a shell o crear demonios.</p>
<p>Entonces, necesitamos crear un demonio php, sin limite de tiempo de ejecucion. Asi podra correr ilimitadamente o hasta que se reinicie el server.</p>
<p><strong>Empezando con el codigo:</strong></p>
<p>Declaramos la IP address donde nos conectaremos y el puerto escucha. Recuerden que debe de estar abierto en caso que haya un firewall.</p>
<pre lang="php">#!/usr/bin/php -q

Vamos a crear un array para las conexiones de datos, (si lo usa para chatear, sería útil para almacenar apodos en el mismo.), Y empezar a crear y escuchar un socket. Por favor tenga en cuenta, que todo lo que se imprime con "echo" va a un archivo "log" en nuestro caso.
<pre lang="php"> $_sockets = array();

if (($master = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) &lt; 0)
{
  echo "socket_create() failed, reason: " . socket_strerror($master) . "\n";
}

socket_set_option($master, SOL_SOCKET,SO_REUSEADDR, 1);

if (($ret = socket_bind($master, $address, $port)) &lt; 0)
{
  echo "socket_bind() failed, reason: " . socket_strerror($ret) . "\n";
}

if (($ret = socket_listen($master, 5)) &lt; 0)
{
  echo "socket_listen() failed, reason: " . socket_strerror($ret) . "\n";
}
else
{
  $started=time();
  echo "[".date('Y-m-d H:i:s')."] SERVER CREATED ( MAXCONN:".SOMAXCONN." ) \n";
  echo "[".date('Y-m-d H:i:s')."] Listening on ".$address.":".$port."\n";
}

$read_sockets = array($master);</pre>
<p>SOMAXCONN es una variable que establece el número de conexiones que puede manejar su máquina. En el mundo Unix se puede ajustar en tiempo de compilación del kernel, o se puede ajustar via sysctl.<br />
Después de esto vamos a crear un bucle persistente para tramitar las solicitudes.</p>
<pre lang="php">while (true)
{
  $changed_sockets = $read_sockets;
  $num_changed_sockets = socket_select($changed_sockets, $write = NULL, $except = NULL, NULL);

  foreach($changed_sockets as $socket)
  {
    if ($socket == $master)
    {
	   if (($client = socket_accept($master)) &lt; 0)
	   {
       echo "socket_accept() failed: reason: " . socket_strerror($msgsock) . "\n";
    	 continue;
	   }
	   else
	   {
	     array_push($read_sockets, $client);
	     echo "[".date('Y-m-d H:i:s')."] CONNECTED "."(".count($read_sockets)."/".SOMAXCONN.")\n";
	   }
    }
    else
    {
      $bytes = @socket_recv($socket, $buffer, 2048, 0);
      /*

      Here comes the core... <img src='http://bodegaweb.com/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> 

      */
    }
}</pre>
<p>Así pues, estos son los conceptos básicos. Hasta este punto, este código es casi el mismo que Raymond Fain del socketShell.php antes mencionados.</p>
<p>Como ya he comentado vamos a editar sólo una parte del código.<br />
Por lo que cada código que cito ahora, irá dentro de el bucle principal. Despues definiremos las funciones. Estas funciones se van fuera, el bucle.<br />
Lo ideal para realizar un servidor de sockets, es que cuente con los permisos "cross-domain-policy", ya que asi posibilita la interaccion entre servidores con flash.</p>
<p>El "Cross-domain-policy" es una serie de datos, en formato XML, que se parece a esto, en nuestro caso:<br />
Por lo tanto, almacenarla en una variable, y si se hace una solicitud debemos mostrarlo:</p>
<pre lang="php">if (preg_match("/policy-file-request/i", $buffer) || preg_match("/crossdomain/i", $buffer))
{
  echo "[".date('Y-m-d H:i:s')."] CROSSDOMAIN.XML REQUEST\n";
  $contents='';

  socket_write($socket,$contents);
  $contents="";

  $index = array_search($socket, $read_sockets);
  unset($read_sockets[$index]);
  socket_shutdown($socket, 2);
  socket_close($socket);
}</pre>
<p>Al recibir una peticion de cross-domain-policy debemos cerrar el socket, ya que si se envia correctamente el permiso entonces se abre un socket nuevo con la conexion adecuada.<br />
Ahora, cuando un usuario pierde la conexion, se sale del sitio o cualquier otra razon, debemos de cortar el socket y borrar sus variables.</p>
<pre lang="php">if (strlen($buffer) == 0)
{
  //we get the user's uniqe id from the database
  $id=$_sockets[intval($socket)]['nick'];

  $index = array_search($socket, $read_sockets);

  unset($read_sockets[$index]); // we clean up
  unset($_sockets[intval($socket)]); // we clean up our own data
  // cleaning up is essential when creating a daemon
  // we can't leave junk in the memory
  @socket_shutdown($socket, 2);
  @socket_close($socket);

  $allclients = $read_sockets; // reload active clients

  // $socket is now pointing to a dead resource id
  // but the send_Message() function will need it, I'll explain later

  send_Message($allclients, "");
  echo "[".date('Y-m-d H:i:s')."] QUIT ".$id."\n";
}</pre>
<p>Y ahora, la comunicacion real del socket:</p>
<pre lang="php">else
{
  $allclients = $read_sockets;
  array_shift($allclients);

  $piece = explode(" ",trim($buffer)); // we strip out all unwanted data
  $cmd = strtoupper($piece[0]);
}</pre>
<p>Suponiendo un codigo como el del protocolo IRC: <em><strong>MSG</strong> PARA MENSAJE</em></p>
<p>Debemos separar por medio del "espacio" para formar un array, y detectar el codigo que vamos a efectuar, despues, unir el resto que sera el "mensaje":</p>
<pre lang="php">if (!empty($piece[1])) $content = $piece[1];

switch ($cmd)
{
  case "IDENTIFY":
    $id = trim($piece[1]);
    $passwd = trim($piece[2]);
    send_Identify($allclients, $socket, $id, $passwd);
  break;

  case "MSG":
    $id = trim($piece[1]);
    $msg="";
    foreach ($piece as $key=&gt;$val)
    {
      if ($key &gt; "1") $msg.=$val." ";
    }
    $msg = trim($msg);
    send_Msg($allclients, $socket, $id, $msg);
  break;

  case "LIST":
    list_Users($allclients, $socket);
    break;
}</pre>
<p>Ahora, vamos con las funciones, declaradas despues del bucle. Debemos recalcar, que para enviar datos al cliente debemos de anexar un chr(0) por alguna razon de la comunicacion.</p>
<pre lang="php">function send_Identify($allclients, $socket, $id, $passwd)
{
  global $_sockets;
  $nicks = array();

  $dbconf = new DATABASE_CONFIG;

  $db_host = $dbconf-&gt;host;
  $db_base = $dbconf-&gt;database;
  $db_login = $dbconf-&gt;login;
  $db_password = $dbconf-&gt;password;

  foreach ($_sockets as $_socket)
  {
    foreach ($_socket as $key=&gt;$val)
    {
      if (empty($nicks[$val])) $nicks[$val]=1;
      else $nicks[$val]=$nicks[$val]+1;
    }
  }

  if (empty($nicks[$id]))
  {
    $s=1;
    //  Here will be a simple authentication.

    $link = mysql_connect($db_host, $db_login, $db_password);
    if (!$link) die("Could not connect:" . mysql_error() . "\n");

    $db_selected = mysql_select_db($db_base, $link);
    if (!$db_selected) die("Can't use $db_base :" . mysql_error() . "\n");

    $result = mysql_query("SELECT nick FROM members WHERE id='".intval($id)."' AND password='".crypt($passwd)."' AND active='1' LIMIT 1");
    $data = mysql_fetch_array($result);
    $name = $data['name'];
    $_sockets[intval($socket)]=array('id'=&gt;$id, 'nick'=&gt;$name);

    mysql_free_result($result);
    mysql_close($link);</pre>
<p>Es escencial que cerremos la conexion a la base de datos, que si no en un par de horas se acomularan los intentos de conexion a la base de datos y se colapsara el server.</p>
<pre lang="php">  }
  else $s=0;

  //   We'll answer to the flash in XML form.
  //   But we receive in plain text format.

  if ($s == 1)
  {
    $out = "";
    send_Message($allclients, "");
    // this goes to all active, identified clients
    echo "[".date('Y-m-d H:i:s')."] LOGIN ".$id."(".count($allclients)."/".SOMAXCONN.")\n";
  }
  else $out = "";

  socket_write($socket, $out.chr(0)); // write back to the client
}

function send_Msg($allclients,$socket,$id,$msg)
{
    global $_sockets;

    if (!empty($_sockets[intval($socket)]))
    {
        $nicks = array(); //amig fut a parancs ebben vannak a nickek.

        foreach ($_sockets as $_socket)
        {
             foreach ($_socket as $key=&gt;$val)
             {
                  // this check's the onliners
                  if (empty($nicks[$val])) $nicks[$val]=1;
                  else $nicks[$val]=$nicks[$val]+1; // we shouldn't have duplicated nicks, but what if...
             }
        }

        foreach($allclients as $client)
        {
            if (!empty($_sockets[$client]['nick']) &amp;&amp; ($_sockets[$client]['nick'] == $id))
            {
              $_client = $client;
              $out = "";
            }
            elseif(empty($nicks[$id]))
            //not online or something similar
            {
               //backto the sender
               $_client = $socket;
               $out = "";
            }
        }
    }
    else
    {
        //backto the sender
        $_client = $socket;
        $out = "";
    }
    if (!empty($out))
    {
       socket_write($socket, $out.chr(0)); //send to back ourself. we have to handle it in flash
       socket_write($_client, $out.chr(0)); //send to the recipient
    }
}</pre>
<p>Ahora creamos la funcion encargada de enviar un mensaje a todos los conectados:</p>
<pre lang="php">    function send_Message($allclients, $socket, $buf)
    {
      global $_sockets;

      foreach($allclients as $client)
      {
        @socket_write($client, $buf.chr(0));
      }
    }

    function list_Users($allclients,$socket)
    {
      global $_sockets;
      $out = "";
      foreach($allclients as $client)
      {
        if (!empty($_sockets[$client]['nick']) &amp;&amp; ($_sockets[$client]['nick'] != ""))
        {
          $out .= "";
        }
      }
      $out .= "";
      socket_write($socket, $out.chr(0));
    }
?&gt;</pre>
<p>Y eso es todo por parte de PHP, que basicamente es lo primordial para entender el funcionamiento, de ahi podemos agregar mas funciones y comandos.<br />
<strong><a href="http://bodegaweb.com/wp-content/uploads/2009/03/phpircgateway.rar" target="_blank">El archivo fuente PHP esta AQUI</a></strong><br />
El archivo FLASH lo publicare mas adelante.<br />
Les dejo un codigo BASH de regalo que es para arrancar el demonio php.</p>
<pre lang="php">#!/bin/sh
if [ "X$1" = "Xstart" ] ; then
    chmod +x /var/www/chat/phpircgateway.php
    /var/www/chat/phpircgateway.php &gt;&gt; /var/log/chat/chat.log &amp;
    echo "Starting chat"
fi</pre>
</pre>
]]></content:encoded>
			<wfw:commentRss>http://bodegaweb.com/servidor-de-sockets-en-php.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
