Ir al contenido
wannacode

Cómo funciona internet

En resumen: Internet es una red de redes: la página viaja en paquetes entre direcciones IP, el DNS traduce el nombre del sitio a una dirección, y el navegador y el servidor hablan por HTTP.

Problema

Entre Enter y la página

Escribes shop.example.bg en el navegador, pulsas Enter y medio segundo después ves el catálogo de café y té. La página está en una computadora de otra ciudad, quizá de otro país. ¿Cómo la encuentra el navegador? ¿Cómo sabe que quieres el catálogo y no el carrito? ¿Qué se dicen exactamente los dos programas?

En la próxima lección escribirás un servidor que responde al navegador. Para hacerlo, necesitas conocer el idioma en el que hablan.

La idea

Paquetes, routers y direcciones IP

Internet es una red de redes: el router de tu casa, la red de tu proveedor, las redes de países y de centros de datos, todas conectadas entre sí.

  • Los datos no viajan en una sola pieza. Se dividen en paquetes, partes pequeñas de unos 1500 bytes cada una. Cada paquete lleva la dirección a la que va.
  • Un router es un aparato que recibe un paquete y lo envía a la siguiente red del camino. Un paquete pasa por 10 a 20 routers, y cada uno lo acerca a su destino.
  • Una dirección IP es el número de un dispositivo en la red, por ejemplo 93.184.215.14. Tu propia computadora siempre se puede llamar localhost (127.0.0.1).
  • Un puerto es un número de 0 a 65 535 para un programa de esa computadora. La dirección IP es el edificio, y el puerto es el apartamento. Los servidores web suelen escuchar en el 80 (HTTP) y el 443 (HTTPS).

Las reglas para hablar se llaman protocolos. IP entrega paquetes sueltos, pero no promete que lleguen. TCP se apoya en IP: crea una conexión entre dos programas, numera los paquetes, los ordena y vuelve a enviar los que se pierden. Por eso los dos juntos se llaman TCP/IP.

Más precisamente, para curiosos
  • Las direcciones como 93.184.215.14 son IPv4: cuatro números de 0 a 255, unos 4000 millones de direcciones. No alcanzan, así que también existe IPv6: 2606:2800:21f:cb07:6820:80da:af6b:8b2c.
  • Además de TCP existe UDP: sin conexión y sin reenviar lo perdido, pero más rápido. Se usa para voz y video en directo y para juegos. La web funciona sobre TCP.
  • Los dos extremos de una conexión TCP se llaman sockets: una dirección y un puerto en cada lado. El puerto del navegador se elige solo, entre los libres.

La idea

Un nombre en lugar de un número: DNS

Las personas recuerdan nombres, las computadoras buscan por dirección IP. Un dominio es el nombre humano de un sitio: shop.example.bg. El DNS (Domain Name System, sistema de nombres de dominio) convierte el nombre en una dirección:

  1. El navegador pregunta al servidor DNS del proveedor: «¿cuál es la dirección de shop.example.bg?»
  2. Si no la sabe, pregunta a lo largo de la cadena: al servidor de .bg y luego al servidor de example.bg.
  3. La respuesta es una dirección IP. El navegador la recuerda durante un tiempo y la próxima vez no pregunta.

Solo entonces el navegador se conecta por TCP a esa dirección, en el puerto 443.

El viaje completo de una página, con la parte de la dirección que usa cada paso:

Uri address = new Uri("https://shop.example.bg/products?category=coffee");
Console.WriteLine("1. DNS: ¿cuál es la dirección de " + address.Host + "?");
Console.WriteLine("2. TCP: conexión al puerto " + address.Port);
Console.WriteLine("3. HTTP: GET " + address.PathAndQuery);
Paso a paso, en palabras
  1. La dirección dice todo lo necesario: con qué protocolo, a qué computadora y qué recurso.
  2. Primero el nombre: el navegador pregunta al DNS cuál es la dirección IP de shop.example.bg.
  3. El DNS responde con una dirección IP, por ejemplo 93.184.215.14. El navegador la recuerda.
  4. Una conexión TCP con esa dirección. El puerto no está en la dirección, así que es el 443, el de https.
  5. Por la conexión va una petición HTTP: el método GET y la ruta /products?category=coffee.
  6. El servidor responde: estado 200 OK y HTML. El navegador dibuja la página.
  7. Tres pasos: un nombre en una dirección (DNS), una conexión (TCP), una petición y una respuesta (HTTP).

El alojamiento (hosting) es la computadora en la que vive el sitio: un servidor en un centro de datos, siempre encendido y conectado. El dominio apunta al alojamiento: en el DNS dice «shop.example.bg está en esta dirección IP».

Más precisamente, para curiosos
  • Un dominio se registra pagando una cuota anual a través de un registrador: una empresa acreditada para esa terminación (.bg, .com, .eu). El registro es por un plazo fijo, normalmente un año, y se renueva. Si no lo renuevas, el nombre queda libre y cualquiera puede quedárselo. Un buen dominio es corto, fácil de recordar y dice para qué es el sitio.
  • Hay varios tipos de alojamiento. Compartido: muchos sitios en un servidor, barato, pero tus vecinos te afectan. VPS (servidor privado virtual): tu propia parte de un servidor con recursos garantizados. Nube: pagas lo que usas y creces cuando lo necesitas. Servidor dedicado: una máquina entera solo para ti. La elección depende de las visitas, de los recursos que necesitas y del presupuesto.

Míralo

La dirección y sus partes

La dirección de una página se llama URL (Uniform Resource Locator, localizador uniforme de recursos). Dice todo lo necesario para llegar a ella. En la documentación también verás el nombre más general URI (Uniform Resource Identifier, identificador uniforme de recursos), y de ahí viene el nombre de la clase. En C#, la clase Uri te da sus partes:

Uri address = new Uri("https://shop.example.bg:8443/products?category=coffee&page=2");
Console.WriteLine("Esquema: " + address.Scheme);
Console.WriteLine("Host: " + address.Host);
Console.WriteLine("Puerto: " + address.Port);
Console.WriteLine("Ruta: " + address.AbsolutePath);
Console.WriteLine("Consulta: " + address.Query);
Uri home = new Uri("https://shop.example.bg/");
Console.WriteLine("Puerto por defecto: " + home.Port);
Salida
Esquema: https
Host: shop.example.bg
Puerto: 8443
Ruta: /products
Consulta: ?category=coffee&page=2
Puerto por defecto: 443
  • Esquema (https): con qué protocolo.
  • Host (shop.example.bg): qué computadora. El nombre pasa por el DNS.
  • Puerto (8443): qué programa de esa computadora. Si no está en la dirección, es el de por defecto para el esquema: 443 para https, 80 para http.
  • Ruta (/products): qué recurso del servidor.
  • Consulta (query, ?category=coffee&page=2): parámetros adicionales como pares nombre=valor, separados por &.

¿Qué imprimirá el programa?

Uri cart = new Uri("http://shop.example.bg/cart?step=2");
Console.WriteLine(cart.Port + " " + cart.AbsolutePath);
Respuesta
Más precisamente, para curiosos
  • Una dirección solo puede contener letras latinas sin acentos, cifras y algunos signos. Todo lo demás, como las letras con tilde y los espacios, se escribe como bytes de UTF-8 con un % delante. El navegador te muestra «té verde», pero por la red va la forma codificada:
Uri search = new Uri("https://shop.example.bg/search?q=té verde");
Console.WriteLine(search.AbsoluteUri);
Console.WriteLine(Uri.UnescapeDataString(search.Query));
Salida
https://shop.example.bg/search?q=t%C3%A9%20verde
?q=té verde
  • Después de la ruta también puede haber un fragmento: #reviews. Nunca llega al servidor: el navegador solo desplaza la página hasta esa parte.

La idea

Una petición HTTP

El navegador ya se ha conectado. Ahora envía una petición HTTP (HyperText Transfer Protocol, protocolo de transferencia de hipertexto). La petición es texto:

Petición
GET /products?category=coffee HTTP/1.1
Host: shop.example.bg
Accept: text/html
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Firefox/131.0
  • La primera línea es el método, la ruta y la versión. El método dice qué quieres: GET es «dame», POST es «aquí tienes unos datos» (un pedido, un formulario). También existen PUT (reemplazar), DELETE (borrar) y otros.
  • Luego vienen las cabeceras (headers), una por línea: nombre: valor. Host dice qué sitio quieres, porque un servidor puede alojar muchos sitios. Accept dice qué entiende el navegador, y User-Agent dice quién es.
  • Una línea vacía termina las cabeceras. Después puede haber un cuerpo: los datos de la petición. GET no tiene cuerpo, POST normalmente sí:
Petición con cuerpo
POST /cart HTTP/1.1
Host: shop.example.bg
Content-Type: application/x-www-form-urlencoded
Content-Length: 19
product=C-101&qty=2

Content-Length dice cuántos bytes tiene el cuerpo, para que el servidor sepa cuándo lo ha recibido entero.

La idea

Una respuesta HTTP

El servidor responde con el mismo tipo de texto. La primera línea lleva el estado: un número y una explicación corta. La primera cifra indica el tipo:

Estado Tipo Ejemplo
2xx éxito 200 OK: aquí tienes lo que pediste
3xx redirección 301 Moved Permanently: ahora está en otra dirección
4xx error en la petición 404 Not Found: no hay tal cosa
5xx error en el servidor 500 Internal Server Error: el programa del servidor falló

Después vienen las cabeceras de la respuesta y el cuerpo: el HTML de la página, JSON con datos, una imagen.

Respuesta
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=utf-8
Content-Length: 31
<h1>No existe ese producto</h1>

Content-Type dice qué es el cuerpo y en qué codificación. En una redirección, la cabecera Location da la nueva dirección, y el navegador envía por sí mismo una nueva petición allí:

Redirección
HTTP/1.1 301 Moved Permanently
Location: https://shop.example.bg/products
Más precisamente, para curiosos
  • HTTP no tiene memoria (es stateless): cada petición va por separado, y el servidor no recuerda las anteriores. Por eso, para «recordarte» en el carrito, el sitio te da una cookie: una cabecera que el navegador devuelve con cada petición siguiente.
  • Un ataque DDoS por HTTP aprovecha esa misma falta de memoria: miles de computadoras infectadas envían una cantidad enorme de peticiones a un servidor. Cada una parece normal, y el servidor tiene que atenderla, hasta que ya no da abasto tampoco con los clientes reales. La defensa está delante del servidor: servicios que filtran el tráfico sospechoso y limitan el número de peticiones desde una misma dirección.

Míralo

La respuesta, desmontada con código

Una respuesta es solo texto, así que puedes desmontarla con los métodos de las cadenas. Cada línea en HTTP termina en \r\n, y la línea vacía entre las cabeceras y el cuerpo es \r\n\r\n:

string response = "HTTP/1.1 200 OK\r\n" +
"Content-Type: text/html; charset=utf-8\r\n" +
"Content-Length: 20\r\n" +
"\r\n" +
"<h1>Café y té</h1>";
string[] parts = response.Split("\r\n\r\n");
string[] lines = parts[0].Split("\r\n");
string[] status = lines[0].Split(' ', 3);
Console.WriteLine("Versión: " + status[0]);
Console.WriteLine("Estado: " + status[1] + " (" + status[2] + ")");
Dictionary<string, string> headers = new Dictionary<string, string>();
for (int i = 1; i < lines.Length; i++)
{
string[] header = lines[i].Split(": ", 2);
headers[header[0]] = header[1];
}
Console.WriteLine("Tipo: " + headers["Content-Type"]);
Console.WriteLine("Longitud: " + headers["Content-Length"] + " bytes");
Console.WriteLine("Cuerpo: " + parts[1]);
Salida
Versión: HTTP/1.1
Estado: 200 (OK)
Tipo: text/html; charset=utf-8
Longitud: 20 bytes
Cuerpo: <h1>Café y té</h1>
  • Split("\r\n\r\n") la divide en dos: la parte de las cabeceras y el cuerpo.
  • La parte de las cabeceras se divide en líneas. La primera es el estado. Split(' ', 3) da como mucho 3 partes: así, con 404 Not Found, la explicación queda entera.
  • Las cabeceras van a un diccionario: nombre → valor. Split(": ", 2) divide solo en el primer : .

Así funciona todo programa que habla HTTP. En la próxima lección, HttpClient lo hará por ti.

Más precisamente, para curiosos
  • Content-Length es 20 bytes, pero el texto tiene 18 caracteres. Por la red van bytes de UTF-8, y ahí cada letra con tilde, como la é, ocupa 2 bytes:
string body = "<h1>Café y té</h1>";
Console.WriteLine(body.Length + " caracteres");
Console.WriteLine(System.Text.Encoding.UTF8.GetByteCount(body) + " bytes");
Salida
18 caracteres
20 bytes
  • Los nombres de las cabeceras no distinguen entre mayúsculas y minúsculas: content-type y Content-Type son lo mismo. Un diccionario que compara así se crea con new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase).
  • HTTP/1.1 es texto. Los más nuevos HTTP/2 y HTTP/3 envían los mismos métodos, cabeceras y estados, pero en forma binaria y con muchas peticiones por una sola conexión. Para tu programa el sentido es el mismo.

Pruébalo

Una cabecera con dos puntos

El programa debería imprimir el nombre y el valor de la cabecera, pero en lugar de la dirección imprime solo https. ¿En qué línea está el error?

Elige la línea con el error.

La idea

HTTPS: lo mismo, pero con candado

HTTP es texto plano. Cualquier router del camino puede leer tu contraseña o cambiar el precio. HTTPS es HTTP sobre TLS (el nombre antiguo es SSL):

  1. Saludo inicial (handshake). El navegador y el servidor acuerdan cómo cifrar e intercambian claves.
  2. Certificado. El servidor muestra un certificado firmado por una organización en la que el navegador confía. Así sabes que hablas con el verdadero shop.example.bg y no con alguien que está en medio.
  3. Cifrado. A partir de ahí, las peticiones y las respuestas viajan cifradas. Por el camino se ve a qué servidor vas, pero no lo que se dicen.

Los métodos, las cabeceras y los estados son los mismos que en HTTP. El candado en la barra de direcciones significa que la conexión va por HTTPS.

La idea

Qué hace el navegador

La primera respuesta es HTML: el texto y la estructura de la página. El navegador lo lee y encuentra en él más recursos: estilos (CSS), programas (JavaScript), imágenes, fuentes. Para cada uno envía una nueva petición. Una página normal hace decenas de peticiones antes de estar lista. Por eso un sitio con muchas imágenes pesadas carga despacio, aunque su HTML sea pequeño.

Después el navegador lo coloca todo y lo dibuja en la pantalla. JavaScript puede cambiar la página después de eso, sin volver a cargarla.

Más precisamente, para curiosos
  • Un navegador tiene varias partes. La interfaz de usuario: la barra de direcciones, los botones, los marcadores, todo menos la propia página. El motor del navegador conecta la interfaz con el motor de renderizado, que entiende HTML y CSS y los dibuja. La parte de red hace las peticiones HTTP. Una capa de dibujo para los controles básicos (listas desplegables, ventanas), igual en todos los sistemas operativos. El intérprete de JavaScript ejecuta los scripts. El almacenamiento guarda las cookies y los datos de los sitios (localStorage, IndexedDB).
  • Cómo se dibuja: a partir del HTML, el navegador construye un árbol de elementos (el DOM), y a partir del CSS, un árbol de estilos (el CSSOM). Juntos dan el árbol de renderizado (render tree). Luego calcula dónde va cada elemento y qué tamaño tiene (layout), y al final dibuja (paint). JavaScript cambia el DOM, y el navegador vuelve a dibujar solo lo afectado.
  • Para leer más: Cómo funciona internet, Qué es HTTP, Cómo funcionan los navegadores y Ataques DDoS con peticiones HTTP (en inglés).

Ejercicio

Direcciones, estados y peticiones

Resuelve estos ejercicios en tu editor.

1. Partes de una dirección. Para https://shop.example.bg/search?q=espresso&max=30&page=2, imprime el host, el puerto y la ruta. Después divide la consulta en pares dentro de un diccionario (TrimStart('?') quita el signo de interrogación, y luego Split('&') y Split('=')), imprímelos y obtén el número de página como número:

Salida
Host: shop.example.bg, puerto 443
Ruta: /search
q = espresso
max = 30
page = 2
Página: 2

2. Qué significa el estado. Un método Meaning(int code) con un switch devuelve el significado de los códigos conocidos 200, 201, 301, 404 y 500. Para los demás da el tipo según la primera cifra (code / 100), y para un tipo desconocido devuelve «código desconocido»:

Salida
200: éxito
201: creado
301: movido de forma permanente
404: no existe ese recurso
418: error en la petición
500: error del servidor
503: otro error del servidor

3. Arma una petición. Un método BuildGet(Uri address) devuelve el texto de una petición GET con Host y Accept: text/html, con \r\n al final de cada línea y una línea vacía al final. address.PathAndQuery da la ruta junto con la consulta. Imprímela, reemplazando cada \r\n por el texto visible \r\n y un salto de línea:

Salida
GET /products?category=tea HTTP/1.1\r\n
Host: shop.example.bg\r\n
Accept: text/html\r\n
\r\n

Test

Ponte a prueba

1. ¿Qué hace el DNS?
2. En la dirección https://shop.example.bg/products?category=tea, ¿cuál es el puerto?
3. La respuesta tiene el estado 404. ¿Qué significa?
4. ¿Cómo sabe el cliente dónde terminan las cabeceras y empieza el cuerpo de la respuesta?
5. ¿Qué añade HTTPS a HTTP?

Creado por Ivo Gergov como parte de la campaña de Evo Tech por una educación accesible en programación ·