aboutsummaryrefslogtreecommitdiff
path: root/files/es/web/api/websockets_api/writing_websocket_server/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/es/web/api/websockets_api/writing_websocket_server/index.html')
-rw-r--r--files/es/web/api/websockets_api/writing_websocket_server/index.html244
1 files changed, 244 insertions, 0 deletions
diff --git a/files/es/web/api/websockets_api/writing_websocket_server/index.html b/files/es/web/api/websockets_api/writing_websocket_server/index.html
new file mode 100644
index 0000000000..333e8e8830
--- /dev/null
+++ b/files/es/web/api/websockets_api/writing_websocket_server/index.html
@@ -0,0 +1,244 @@
+---
+title: Escribiendo un servidor WebSocket en C#
+slug: Web/API/WebSockets_API/Escribiendo_servidor_WebSocket
+tags:
+ - HTML5
+ - Tutorial
+ - WebSockets
+translation_of: Web/API/WebSockets_API/Writing_WebSocket_server
+---
+<h2 id="Introducción">Introducción</h2>
+
+<p>Si deseas utilizar la API WebSocket, es conveniente si tienes un servidor. En este artículo te mostraré como puedes escribir uno en C#. Tú puedes hacer esto en cualquier lenguaje del lado del servidor, pero para mantener las cosas simples y más comprensibles, elegí el lenguaje de Microsoft<span style="line-height: 1.5;">.</span></p>
+
+<p>Este servidor se ajusta a <a href="http://tools.ietf.org/html/rfc6455" title="http://tools.ietf.org/html/rfc6455">RFC 6455</a> por lo que solo manejará las conexiones de Chrome version 16, Firefox 11, IE 10 and superiores.</p>
+
+<h2 id="Primeros_pasos">Primeros pasos</h2>
+
+<p>WebSocket se comunica a través de conexiones <a href="https://es.wikipedia.org/wiki/Transmission_Control_Protocol" title="https://es.wikipedia.org/wiki/Transmission_Control_Protocol">TCP (Transmission Control Protocol)</a>, afortunadamente C# tiene una clase <a href="http://msdn.microsoft.com/es-es/library/system.net.sockets.tcplistener.aspx" title="http://msdn.microsoft.com/en-us/library/system.net.sockets.tcplistener.aspx">TcpListener</a> la cual hace lo que su nombre sugiere. Esta se encuentra en el namespace <em>System.Net.Sockets</em>.</p>
+
+<div class="note">
+<p><span style="line-height: 1.572;">Es una buena idea usar la instrucción <code>using</code></span><span style="line-height: 1.572;"> para escribir menos. Eso significa que no tendrás que re escribir el namespace de nuevo en cada ocasión.</span></p>
+</div>
+
+<h3 id="TcpListener">TcpListener</h3>
+
+<p>Constructor:</p>
+
+<pre class="brush: cpp">TcpListener(System.Net.IPAddress localaddr, int port)</pre>
+
+<p><code>localaddr</code> especifica la IP a escuchar y <code>port</code> especifica el puerto.</p>
+
+<div class="note">
+<p>Para crear un objeto <code>IPAddress</code> desde un <code>string</code>, usa el método estático <code>Parse</code> de <code>IPAddres.</code></p>
+</div>
+
+<p><span style="line-height: 1.572;">Métodos</span><span style="line-height: 1.572;">:</span></p>
+
+<ul>
+ <li><code><span style="line-height: 1.572;">Start()</span></code></li>
+ <li><span style="line-height: 1.572;">S<code>ystem.Net.Sockets.<a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx" title="http://msdn.microsoft.com/en-us/library/system.net.sockets.tcpclient.aspx">TcpClient</a> AcceptTcpClient()</code><br>
+ Espera por una conexión TCP, la acepta y la devuelve como un objeto TcpClient.</span></li>
+</ul>
+
+<p><span style="line-height: 1.572;">Aquí está como utilizar lo que hemos aprendido:</span></p>
+
+<pre class="brush: cpp">​using System.Net.Sockets;
+using System.Net;
+using System;
+
+class Server {
+ public static void Main() {
+ TcpListener server = new TcpListener(IPAddress.Parse("127.0.0.1"), 80);
+
+ server.Start();
+ Console.WriteLine("El server se ha iniciado en 127.0.0.1:80.{0}Esperando una conexión...", Environment.NewLine);
+
+ TcpClient client = server.AcceptTcpClient();
+
+ Console.WriteLine("Un cliente conectado.");
+ }
+}
+</pre>
+
+<h3 id="TcpClient"><span style="line-height: 1.572;">TcpClient</span></h3>
+
+<p>Métodos:</p>
+
+<ul>
+ <li><code>System.Net.Sockets.<a href="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx" title="http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.aspx">NetworkStream</a> GetStream()</code><br>
+ Obtiene el stream del canal de comunicación. Ambos lados del canal tienen capacidad de lectura y escritura.</li>
+</ul>
+
+<p>Propiedades:</p>
+
+<ul>
+ <li><code>int Available</code><br>
+ Este es el número de bytes de datos que han sido enviados. El valor es cero hasta que <code><em>NetworkStream.DataAvailable</em></code> es <code><em>true</em></code>.</li>
+</ul>
+
+<h3 id="NetworkStream">NetworkStream</h3>
+
+<p>Métodos:</p>
+
+<pre class="brush: cpp">Write(Byte[] buffer, int offset, int size)</pre>
+
+<p>Escribe bytes desde el <em>buffer;</em> el <em>offset</em> y el <em>size</em> determinan la longitud del mensaje.</p>
+
+<pre><span class="brush: cpp" style="line-height: 1.572;">Read(Byte[] buffer, int offset, int size)</span></pre>
+
+<p>Lee bytes al <em>buffer;</em> el <em>offset</em> y el <em>size </em>determinan la longitud del mensaje.</p>
+
+<p>Ampliemos nuestro ejemplo anterior.</p>
+
+<pre class="brush: cpp">TcpClient client = server.AcceptTcpClient();
+
+Console.WriteLine("Un cliente conectado.");
+
+NetworkStream stream = client.GetStream();
+
+//enter to an infinite cycle to be able to handle every change in stream
+while (true) {
+ while (!stream.DataAvailable);
+
+ Byte[] bytes = new Byte[client.Available];
+
+ stream.Read(bytes, 0, bytes.Length);
+}</pre>
+
+<h2 id="Handshaking">Handshaking</h2>
+
+<p>Cuando un cliente se conecta al servidor, envía una solicitud GET para actualizar la conexión al WebSocket desde una simple petición HTTP. Esto es conocido como <em>handshaking</em>.</p>
+
+<p>Este código de ejemplo detecta el GET desde el cliente. Nota que esto bloqueará hasta los 3 primeros bytes del mensaje disponible. Soluciones alternativas deben ser investigadas para ambientes de producción.</p>
+
+<pre><code>using System.Text;
+using System.Text.RegularExpressions;
+
+while(client.Available &lt; 3)
+{
+ // wait for enough bytes to be available
+}
+
+Byte[] bytes = new Byte[client.Available];
+
+stream.Read(bytes, 0, bytes.Length);
+
+//translate bytes of request to string
+String data = Encoding.UTF8.GetString(bytes);
+
+if (Regex.IsMatch(data, "^GET")) {
+
+} else {
+
+}</code></pre>
+
+<p>Esta respuesta es fácil de construir, pero puede ser un poco díficil de entender. La explicación completa del <em>handshake </em>al servidor puede encontrarse en  <a href="https://developer.mozilla.org/es/docs/WebSockets-840092-dup/RFC%206455,%20section%204.2.2">RFC 6455, section 4.2.2</a>. Para nuestros propósitos, solo construiremos una respuesta simple.</p>
+
+<p>Debes:</p>
+
+<ol>
+ <li>Obtener el valor de "<em>Sec-WebSocket-Key" </em>sin espacios iniciales ni finales de el encabezado de la solicitud</li>
+ <li>Concatenarlo con "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"</li>
+ <li>Calcular el código SHA-1 y Base64</li>
+ <li>Escribe el valor <em>Sec-WebSocket-Accept</em> en el encabezado como parte de la respuesta HTTP.</li>
+</ol>
+
+<pre class="brush: cpp">if (new Regex("^GET").IsMatch(data)) {
+ Byte[] response = Encoding.UTF8.GetBytes("HTTP/1.1 101 Switching Protocols" + Environment.NewLine
+ + "Connection: Upgrade" + Environment.NewLine
+ + "Upgrade: websocket" + Environment.NewLine
+ + "Sec-WebSocket-Accept: " + Convert.ToBase64String (
+ SHA1.Create().ComputeHash (
+ Encoding.UTF8.GetBytes (
+ new Regex("Sec-WebSocket-Key: (.*)").Match(data).Groups[1].Value.Trim() + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
+ )
+ )
+ ) + Environment.NewLine
+ + Environment.NewLine);
+
+ stream.Write(response, 0, response.Length);
+}
+</pre>
+
+<h2 id="Decoding_messages">Decoding messages</h2>
+
+<p>Luego de un <em>handshake</em> exitoso el cliente puede enviar mensajes al servidor, pero estos serán codificados.</p>
+
+<p>Si nosotros enviamos "MDN", obtendremos estos bytes:</p>
+
+<table>
+ <tbody>
+ <tr>
+ <td>129</td>
+ <td>131</td>
+ <td>61</td>
+ <td>84</td>
+ <td>35</td>
+ <td>6</td>
+ <td>112</td>
+ <td>16</td>
+ <td>109</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>- 129:</p>
+
+<table>
+ <thead>
+ <tr>
+ <th scope="col">FIN (¿Es el mensaje completo?)</th>
+ <th scope="col">RSV1</th>
+ <th scope="col">RSV2</th>
+ <th scope="col">RSV3</th>
+ <th scope="col">Opcode</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td>1</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0</td>
+ <td>0x1=0001</td>
+ </tr>
+ </tbody>
+</table>
+
+<p>FIN: Puedes enviar tu mensaje en marcos, pero ahora debe mantener las cosas simples.<br>
+ <span style="line-height: 1.572;">Opcode </span><em>0x1</em><span style="line-height: 1.572;"> significa que es un texto. </span><a href="http://tools.ietf.org/html/rfc6455#section-5.2" style="line-height: 1.572;" title="http://tools.ietf.org/html/rfc6455#section-5.2">Lista completa de Opcodes</a></p>
+
+<p>- 131:</p>
+
+<p>Si el segundo byte menos 128 se encuentra entre 0 y 125, esta es la longitud del mensaje. Si es 126, los siguientes 2 bytes (entero sin signo de 16 bits), si es 127, los siguientes 8 bytes (entero sin signo de 64 bits) son la longitud.</p>
+
+<div class="note">
+<p>Puedo tomar 128, porque el primer bit siempre es 1.</p>
+</div>
+
+<p>- 61, 84, 35 y 6 son los bytes de la clave a decodificar. Cambian en cada oportunidad.</p>
+
+<p>- Los bytes codificados restantes son el mensaje<span style="line-height: 1.572;">.</span></p>
+
+<h3 id="Algoritmo_de_decodificación">Algoritmo de decodificación</h3>
+
+<p>byte decodificado = byte codificado XOR (posición del byte codificado Mod 4) byte de la clave</p>
+
+<p>Ejemplo en C#:</p>
+
+<pre class="brush: cpp">Byte[] decoded = new Byte[3];
+Byte[] encoded = new Byte[3] {112, 16, 109};
+Byte[] key = Byte[4] {61, 84, 35, 6};
+
+for (int i = 0; i &lt; encoded.Length; i++) {
+ decoded[i] = (Byte)(encoded[i] ^ key[i % 4]);
+}</pre>
+
+<h2 id="Relacionado">Relacionado</h2>
+
+<ul>
+ <li><a href="/es/docs/WebSockets/Writing_WebSocket_servers">Escribiendo servidores WebSocket</a></li>
+</ul>
+
+<div id="cke_pastebin" style="position: absolute; top: 2209.23px; width: 1px; height: 1px; overflow: hidden; left: -1000px;"> </div>