Herramientas de usuario

Herramientas del sitio


informatica:programacion:cursos:python_avanzado_proyectos_seguridad:servidor_web_sockets

¡Esta es una revisión vieja del documento!


Implementar en Python un servidor HTTP

Módulo perteneciente al curso Python avanzado para proyectos de seguridad

Podríamos crear un socket del tipo TCP y vincularlo a un puerto. Podríamos utilizar “localhost”, para aceptar conexiones desde la misma máquina. El puerto podría ser 80, pero como necesita privilegios de root, usaremos uno mayor o igual que 8080.

HTTP (Hyper Text Transfer Protocol) es un protocolo base de la web y que ofrece un conjunto de instrucciones para que los servidores y navegadores funcionen

Un protocolo es un formato o conjunto definido de reglas, procedimientos que permiten inter-operar a dos dispositivos. Un protocolo sirve para la comunicación en red o entre aplicaciones

Métodos de socket del servidor

Estos son los principales métodos que podemos usar desde el punto de vista del servidor:

  • socket.bind(dirección): este método nos permite conectar la dirección con el socket, con el requisito de que el socket debe estar abierto antes de establecer la conexión con la dirección.
  • socket.listen(numero_conexiones): este método acepta como parámetro el número máximo de conexiones de los clientes e inicia la escucha TCP para las conexiones entrantes.????
  • socket.accept(): este método nos permite aceptar conexiones del cliente. Este método devuelve dos valores: client_socket y la dirección del cliente. client_socket es un nuevo objeto de socket utilizado para enviar y recibir datos. Antes de usar este método, debe llamar a los métodos socket.bind(dirección) y socket.listen(numero_conexiones).

Implementación del servidor

De los métodos comentados anteriormente podríamos utilizar el método bind() que acepta como parámetros la dirección ip y el puerto.

El módulo socket proporciona el método listen() que permite poner en cola hasta un máximo de n solicitudes. Por ejemplo podríamos establecer en 5 el número máximo de peticiones con la instrucción mysocket.listen(5).

Posteriormente, podríamos establecer la lógica de nuestro servidor cada vez que recibe la petición de un cliente. Utilizamos el método accept() para aceptar conexiones, leer datos entrantes con el método recv y respondemos una página HTML con el método send().

import socket
 
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.bind(('localhost', 8080)
mySocket.listen(5)
 
while True:
    print('Esperando conexiones...')
    (recvSocket, address) = mySocket.accept()
    print('Petición HTTP recibida:')
    print(recvSocket.recv(1024))
    recvSocket.send(bytes("HTTP/1.1 200 OK\r\n\r\n <html><body><h1>Hello World!</h1></body></html> \r\n",'utf-8'))
    recvSocket.close()

Al ejecutar el código anterior, el script se quedará en ejecución a la espera de conexiones.

Podemos probar que funciona correctamente haciendo una petición con curl, por ejemplo:

curl localhost:8080

Nos devolvería el documento HTML que indicamos en el código del servidor.

Veremos cómo implementar un cliente HTTP sencillo en Python para probar también el servidor.

Probando el servidor creando un cliente HTTP

Si queremos probar el funcionamiento del servidor HTTP, podríamos crearnos otro script que nos permite obtener la respuesta envía el servidor que hemos creado.

#!/usr/bin/python
import socket
webhost = 'localhost'
webport = 8080
print("Contacting %s on port %d ..." % (webhost, webport))
webclient = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
webclient.connect((webhost, webport))
webclient.send(bytes("GET / HTTP/1.1\r\nHost: localhost\r\n\r\n".encode('utf-8')))
reply = webclient.recv(4096)
print("Response from %s:" % webhost)
print(reply.decode())

Con el servidor HTTP funcionando, ejecutaríamos el cliente y veríamos una respuesta similar a la siguiente:

Contacting localhost on port 8080 ...
Response from localhost:
HTTP/1.1 200 OK</p>

Actividad práctica

Completa el siguiente script para implementar un servidor HTTP que esté escuchando en el puerto 8080 y acepte como máximo 5 conexiones de forma simultánea.

import socket
 
# Crear un socket del tipo TCP y vincularlo a un puerto
# Utilizamos 'localhost', por lo tanto, solo aceptamos conexiones desde la misma máquina
# El puerto podría ser 80, pero como necesita privilegios de root,
# usemos uno por mayor o igual que 8080
 
mySocket = socket.socket(xxx,xxx)
mySocket.bind(('localhost', 8080))
 
# Poner en cola un máximo de 5 solicitudes de conexión TCP
 
xxx.listen(5)
 
# Aceptar conexiones, leer datos entrantes y responder una página HTML (en un bucle)
 
while True:
    print('Waiting for connections')
    (recvSocket, address) = mySocket.xxx()
    print('HTTP request received:')
    print(recvSocket.xxx(1024))
    recvSocket.xxx(bytes("HTTP/1.1 200 OK\r\n\r\n <html><body><h1>Hello World!</h1></body></html> \r\n",'utf-8'))
    xxx.close()

Solución:

import socket
 
# Crear un socket del tipo TCP y vincularlo a un puerto
# Utilizamos 'localhost', por lo tanto, solo aceptamos conexiones desde la misma máquina
# El puerto podría ser 80, pero como necesita privilegios de root,
# usemos uno por mayor o igual que 8080
 
mySocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
mySocket.bind(('localhost', 8080))
 
# Poner en cola un máximo de 5 solicitudes de conexión TCP
mySocket.listen(5)
 
# Aceptar conexiones, leer datos entrantes y responder una página HTML (en un bucle)
 
while True:
    print('Waiting for connections')
    (recvSocket, address) = mySocket.accept()
    print('HTTP request received:')
    print(recvSocket.recv(1024))
    recvSocket.send(bytes("HTTP/1.1 200 OK\r\n\r\n <html><body><h1>Hello World!</h1></body></html> \r\n",'utf-8'))
    recvSocket.close()

Resumen

En esta unidad hemos aprendido:

  • Crear un socket utilizando el constructor s = socket.socket (socket_family, socket_type, protocol = 0) donde indicamos la familia, el tipo y el protocolo.
  • Obtener información con los métodos gethostbyaddr(dirección) que nos permite obtener un nombre de dominio a partir de la dirección IP y gethostbyname(hostname) que nos permite obtener una dirección IP a partir de un nombre de dominio.
  • Gracias al uso del método socket.connect_ex(dirección,puerto) hemos conseguido implementar un escaneo de puertos, pasando como parámetros la dirección ip y el puerto.
  • Implementar nuestro propio servidor HTTP que tiene la capacidad de atender peticiones por parte de n clientes de forma simultánea. Con el uso del método socket.bind(dirección) nos permite conectar la dirección con el socket, con el requisito de que el socket debe estar abierto antes de establecer la conexión.
  • El método socket.listen(numero_conexiones) acepta como parámetro el número máximo de conexiones de los clientes e inicia la escucha TCP para las conexiones entrantes.???
  • Finalmente, implementamos un cliente HTTP para realizar peticiones al servidor creado anteriormente.

FAQ

¿Cuántas familias de direcciones para sockets encontramos en el módulo socket de Python?

  • AF_INET: son las direcciones IPv4. Se representa con el host y el puerto.
  • AF_INET6: son las direcciones IPv6. Se representa con el host y el puerto (así como la etiqueta de flujo “Flow Label” con la documentación en https://tools.ietf.org/html/rfc6437, y el alcance de la id “scope id” que indica el interfaz qué usar)
  • AF_UNIX o AF_LOCAL: son las direcciones locales de Unix. Se representa como un string que apunta a un fichero del sistema.

¿Cuál es la utilidad de los sockets?

Los sockets mantienen la conexión en tiempo real entre un cliente y un servidor con el objetivo de enviar y recibir datos de un lado a otro. Por ejemplo, podremos crear nuestro propio chat; es decir, una aplicación de escritorio en nuestro ordenador recibiendo y enviando mensajes, para que el lado del servidor reciba y envíe los mensajes en tiempo real.

informatica/programacion/cursos/python_avanzado_proyectos_seguridad/servidor_web_sockets.1731337688.txt.gz · Última modificación: por tempwin