Te enseñaremos a construir un servidor web simple en Python

Introducción al socket

Como complemento al tutorial de cliente de red, este tutorial muestra cómo implementar un simple servidor web en Python. Para estar seguros, esto no es un sustituto de Apache o Zope. También hay formas más robustas de implementar servicios web en Python, utilizando módulos como BaseHTTPServer. Este servidor utiliza exclusivamente el módulo socket.

 

Recordará que el módulo de socket es la columna vertebral de la mayoría de los módulos de servicios web de Python. Al igual que con el simple cliente de red, la construcción de un servidor con él ilustra de forma transparente los fundamentos de los servicios web en Python. El propio servidor BaseHTTPS importa el módulo de socket para afectar a un servidor.

Ejecutar servidores

A modo de revisión, todas las transacciones de red se realizan entre clientes y servidores. En la mayoría de los protocolos, los clientes piden una dirección determinada y reciben datos.

Dentro de cada dirección, una multitud de servidores pueden funcionar. El límite está en el hardware. Con suficiente hardware (RAM, velocidad del procesador, etc.), la misma computadora puede servir como servidor web, servidor ftp y servidor de correo (pop, smtp, imap, o todos los anteriores) al mismo tiempo. Cada servicio está asociado a un puerto. El puerto está conectado a un socket. El servidor escucha su puerto asociado y da información cuando se reciben peticiones en ese puerto.

 

Comunicación a través de tomas de corriente

Por lo tanto, para afectar a una conexión de red es necesario conocer el host, el puerto y las acciones permitidas en ese puerto. La mayoría de los servidores web funcionan en el puerto 80. Sin embargo, para evitar conflictos con un servidor Apache instalado, nuestro servidor web se ejecutará en el puerto 8080. Para evitar conflictos con otros servicios, es mejor mantener los servicios HTTP en los puertos 80 u 8080. Estos son los dos más comunes. Obviamente, si se utilizan, debe encontrar un puerto abierto y alertar a los usuarios sobre el cambio.

 

Al igual que con el cliente de red, debe tener en cuenta que estas direcciones son los números de puerto comunes para los diferentes servicios. Mientras el cliente pida el servicio correcto en el puerto correcto y en la dirección correcta, la comunicación seguirá produciéndose. El servicio de correo de Google, por ejemplo, no se ejecutó inicialmente con los números de puerto comunes, pero debido a que saben cómo acceder a sus cuentas, los usuarios todavía pueden recibir su correo.

A diferencia del cliente de red, todas las variables en el servidor están cableadas. Cualquier servicio que se espera que se ejecute constantemente no debe tener las variables de su lógica interna configuradas en la línea de comandos. La única variación de esto sería si, por alguna razón, usted quisiera que el servicio se ejecutara ocasionalmente y en varios números de puerto. Sin embargo, si éste fuera el caso, todavía podría ver la hora del sistema y cambiar las fijaciones en consecuencia.

 

Así que nuestra única importación es el módulo de socket.

 

import socket

 

A continuación, necesitamos declarar algunas variables.

 

Hosts y puertos

Como ya se ha mencionado, el servidor necesita conocer el host al que se va a asociar y el puerto en el que se va a escuchar. Para nuestros propósitos, haremos que el servicio se aplique a cualquier nombre de host.

host = ''

port = 8080

 

El puerto, como se mencionó anteriormente, será el 8080. Tenga en cuenta que, si utiliza este servidor junto con el cliente de red, tendrá que cambiar el número de puerto utilizado en ese programa.

 

Creación de un socket

Ya sea para solicitar información o para servirla, para acceder a Internet, necesitamos crear un socket. La sintaxis de esta llamada es la siguiente:

 

<variable> = socket.socket(<family>, <type>)

 

Las familias de sockets reconocidas son:

 

  • AF_INET: Protocolos IPv4 (TCP y UDP)
  • AF_INET6: Protocolos IPv6 (TCP y UDP)
  • AF_UNIX: Protocolos de dominio UNIX

Los dos primeros son obviamente protocolos de Internet. Cualquier cosa que viaja a través de Internet puede ser accedida en estas familias. Muchas redes todavía no funcionan con IPv6. Por lo tanto, a menos que sepa lo contrario, lo más seguro es predeterminar IPv4 y usar AF_INET.

 

El tipo de socket se refiere al tipo de comunicación que se utiliza a través del socket. Los cinco tipos de sockets son los siguientes:

 

  • SOCK_STREAM: un flujo de bytes TCP orientado a la conexión
  • SOCK_DGRAM: Transferencia UDP de datagramas (paquetes IP autónomos que no dependen de la confirmación cliente-servidor)
  • SOCK_RAW: un socket en bruto
  • SOCK_RDM: para datagramas fiables
  • SOCK_SEQPACKET: transferencia secuencial de registros a través de una conexión

Con mucho, los tipos más comunes son SOCK_STEAM y SOCK_DGRAM porque funcionan en los dos protocolos de la suite IP (TCP y UDP). Los últimos tres son mucho más raros y, por lo tanto, no siempre son compatibles.

 

Así que vamos a crear un socket y asignarlo a una variable.

 

c = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

 

Configuración de las opciones de socket

Después de crear el socket, tenemos que configurar las opciones de socket. Para cualquier objeto socket, puede establecer las opciones de socket utilizando el método setsockopt(). La sintaxis es la siguiente:

 

socket_object.setsockopt(level, option_name, value) Para nuestros propósitos, usamos la siguiente línea:

 

c.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

El término "nivel" se refiere a las categorías de opciones. Para las opciones de nivel de socket, utilice SOL_SOCKET. Para los números de protocolo, se utilizaría IPPROTO_IP. SOL_SOCKET es un atributo constante del socket. El sistema operativo determina exactamente qué opciones están disponibles como parte de cada nivel y si está utilizando IPv4 o IPv6.

 

La documentación para Linux y sistemas Unix relacionados se puede encontrar en la documentación del sistema. La documentación para los usuarios de Microsoft se puede encontrar en el sitio web de MSDN. Al momento de escribir esto, no he encontrado documentación de Mac sobre programación de sockets. Como Mac se basa aproximadamente en Unix BSD, es probable que implemente un complemento completo de opciones.

 

Para garantizar la reutilización de este socket, utilizamos la opción SO_REUSEADDR. Se podría restringir el servidor para que sólo se ejecute en puertos abiertos, pero eso parece innecesario. Tenga en cuenta, sin embargo, que, si dos o más servicios se despliegan en el mismo puerto, los efectos son impredecibles. No se puede estar seguro de qué servicio recibirá qué paquete de información.

Finalmente, el '1' para un valor es el valor por el cual la petición en el socket es conocida en el programa. De esta manera, un programa puede escuchar en un socket de forma muy matizada.

 

Cómo conectar el puerto al socket

Después de crear el socket y configurar sus opciones, necesitamos unir el puerto al socket.

 

c.bind((host, port))

 

Terminada la unión, ahora le decimos a la computadora que espere y escuche en ese puerto.

 

c.listen(1)

 

Si queremos dar feedback a la persona que llama al servidor, ahora podemos introducir un comando de impresión para confirmar que el servidor está funcionando.

Manejo de una solicitud de servidor

Una vez configurado el servidor, ahora necesitamos decirle a Python qué hacer cuando se hace una petición en el puerto dado. Para ello hacemos referencia a la petición por su valor y la usamos como argumento de un bucle persistente.

 

Cuando se realiza una solicitud, el servidor debe aceptarla y crear un objeto de archivo para interactuar con ella.

 

 while 1:

csock, caddr = c.accept()

cfile = csock.makefile('rw', 0)

 

En este caso, el servidor utiliza el mismo puerto para leer y escribir. Por lo tanto, al método makefile se le da un argumento 'rw'. La longitud nula del tamaño del búfer simplemente deja que esa parte del archivo se determine dinámicamente.

Envío de datos al cliente

A menos que queramos crear un servidor de acción única, el siguiente paso es leer la entrada del objeto de archivo. Cuando lo hagamos, debemos tener cuidado de eliminar el exceso de espacio en blanco.

 

 line = cfile.readline().strip()

 

La solicitud se presentará en forma de una acción, seguida de una página, el protocolo y la versión del protocolo que se está utilizando. Si se quiere servir una página web, se divide esta entrada para recuperar la página solicitada y luego se lee esa página en una variable que luego se escribe en el objeto del archivo de socket. Una función para leer un archivo en un diccionario se puede encontrar en el blog.

 

Para que este tutorial sea un poco más ilustrativo de lo que se puede hacer con el módulo de socket, renunciaremos a esa parte del servidor y en su lugar mostraremos cómo se puede matizar la presentación de los datos. Introduzca las siguientes líneas en el programa.

 cfile.write('HTTP/1.0 200 OK\n\n')

cfile.write('<html><head><title>Welcome %s!</title></head>' %(str(caddr)))

cfile.write('<body><h1>Follow the link...</h1>')

cfile.write('All the server needs to do is ')

cfile.write('to deliver the text to the socket. ')

cfile.write('It delivers the HTML code for a link, ')

cfile.write('and the web browser converts it. <br><br><br><br>')

cfile.write('<font size="7"><center> <a href="http://python.about.com/index.html">Click me!</a> </center></font>')

cfile.write('<br><br>The wording of your request was: "%s"' %(line))

cfile.write('</body></html>')

 

Análisis final y puesta fuera de servicio

Si se está enviando una página web, la primera línea es una buena manera de introducir los datos en un navegador web. Si se omite, la mayoría de los navegadores web por defecto renderizan HTML. Sin embargo, si se incluye, el 'OK' debe ir seguido de dos nuevos caracteres de línea. Se utilizan para distinguir la información de protocolo del contenido de la página.

 

La sintaxis de la primera línea, como probablemente pueda suponer, es protocolo, versión de protocolo, número de mensaje y estado. Si alguna vez ha ido a una página web que se ha movido, es probable que haya recibido un error 404. El mensaje 200 aquí es simplemente el mensaje afirmativo.

El resto de la salida es simplemente una página web dividida en varias líneas. Observará que el servidor puede ser programado para utilizar datos de usuario en la salida. La línea final refleja la solicitud web tal y como fue recibida por el servidor.

 

Finalmente, como los actos de cierre de la petición, necesitamos cerrar el objeto de archivo y el socket del servidor.

 

 cfile.close()

csock.close()

 

Ahora guarde este programa bajo un nombre reconocible. Después de llamarlo con 'python program_nombre_del_programa.py', si programó un mensaje para confirmar que el servicio está en ejecución, éste se imprimirá en la pantalla. El terminal parecerá entonces detenerse. Todo es como debe ser. Abra su navegador web y vaya a localhost:8080. A continuación, debería ver la salida de los comandos de escritura que le dimos. Por favor, tenga en cuenta que, por el bien del espacio, no he implementado el manejo de errores en este programa. Sin embargo, cualquier programa liberado en el `salvaje' debería. Ver "Tratamiento de errores en Python" para más información.

 

 

 

(0 votes)