Cargando



Manipulación de sockets con Python

En este tutorial veremos cómo podemos hacer la manipulación de los sockets de nuestro equipo con el lenguaje de programación Python.


dic 05 2014 06:05
Profesional
dic 05 2014 11:32
Los sockets son la interfaz que nos permite comunicar dos o más equipos a través de una red. Gracias a ello podemos crear diferentes tipos de aplicaciones que nos ayuden a transmitir datos a través de Internet y así ver resultados que de otra forma no tendríamos en tiempo real.

Una de las formas más comunes de implementar los sockets es a través del protocolo TCP, esto ayuda a que con el apoyo del sistema operativo la transmisión vía Internet se de manera normal y sin problemas.

Manipular el tiempo de espera del socket


Ya que conocemos un poco el concepto básico de lo que es sockets, vamos a empezar por manipular sus características, una de ellas es el tiempo de espera.

Tiempo de espera
El tiempo de espera nos permite establecer la cantidad de tiempo que puede el socket estar atento para recibir o enviar datos, esto es muy importante ya que si existe un bloqueo de la aplicación mientras esta este tiempo en espera podemos sufrir el riesgo de ralentizar todo un sistema. Es por ello que estamos en la necesidad de poder saber cuál es el tiempo de espera predeterminado y también poder establecer uno nosotros mismos para nuestra conveniencia.


Para lograr esto podemos utilizar un par de métodos que existen con esa finalidad dentro de la librería estándar socket de Python.

gettimeout()
El primer método es gettimeout() y como su nombre lo indica nos ofrece el tiempo de espera inicial del socket que le pasemos como parámetro.


settimeout()
El segundo método es settimeout() y su funcionalidad es establecer un tiempo de espera para el socket en cuestión expresado en milisegundos.


Estableciendo el tiempo de espera


Vamos a crear ahora un pequeño programa que nos permita poner en acción lo que hemos aprendido, para ello vamos en primer lugar a crear un objeto del tipo socket que servirá como nuestro sujeto de pruebas, para ello le pasaremos la familia y el tipo de socket al constructor y con ello podremos aplicar los métodos.

Para poder ver los cambios una vez que hemos creado nuestro socket imprimiremos su tiempo de espera que debe ser nulo porque es un objeto nuevo, luego con el método settimeout() le estableceremos un nuevo tiempo de espera y finalmente vamos a imprimir la información, así confirmaremos que todo ha funcionado como debía.

Para lograr todo esto debemos asegurarnos de tener Python instalado en nuestro sistema, en su versión 2.7, y tener un editor de texto para poder crear los archivos con los programas, aunque también podemos hacer el ejercicio en la consola, sin embargo es un poco más incómodo y no es persistente, lo que quiere decir que perderíamos nuestro trabajo. Veamos el código fuente de este ejemplo:

#!/usr/bin/env python

import socket
def tiempo_espera_socket():
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
print "El tiempo de espera inicial es: %s" %s.gettimeout()
s.settimeout(100)
print "El nuevo tiempo de espera es: %s" %s.gettimeout()

if __name__ == '__main__':
tiempo_espera_socket()

Esto lo vamos a guardar en un nuevo archivo llamado socketTiempoEspera.py y lo ejecutaremos en consola, el resultado debe ser algo similar a lo siguiente:

manipulacion-sockets-python.jpg


Manipular el tamaño del buffer de un socket


El buffer es otra de las cosas que debemos tomar en cuenta cuando trabajamos con sockets, ya que este componente es el que nos va a indicar la cantidad de datos que podemos transmitir al momento, a mayor cantidad de buffer mayor es la cantidad de datos, sin embargo esto significa también más consumo de recursos y un mayor tiempo de espera en la transmisión de los mismos. En caso contrario un menor buffer representa más velocidad aunque limita la cantidad de datos a trasladar, es por ello que es una habilidad que debemos dominar.

setsockopt()
Para ayudarnos a manipular el buffer la librería socket de Python nos ofrece el método setsockopt(), el cual debemos aplicar sobre una instancia de la clase socket. Si deseamos cambiar el tamaño del buffer seguramente debemos saber en primer lugar el tamaño original del buffer del socket, para ello también tenemos el método getsockopt() y se utiliza de forma muy similar al método que describimos anteriormente.


Estableciendo el tamaño del buffer


Vamos a crear un pequeño programa para demostrar lo que hemos explicado anteriormente, en el código que veremos vamos en primer lugar a crear un par de constantes que utilizaremos en nuestro programa y serán definidas a 4096 lo que es un valor para el tamaño de los buffers que estableceremos.

Luego hacemos una instancia de la clase socket, para inmediatamente pedir los tamaños iniciales del buffer, luego los imprimimos por pantalla.

Finalmente utilizaremos el método setsockopt() para establecer el tamaño que deseamos del buffer utilizando las constantes definidas al inicio del programa, este método recibe tres parámetros, el nivel , el nombre y finalmente el valor para el buffer.

Veamos el código que nos ayuda a especificar lo que hemos explicado, vamos a guardarlo en un archivo llamado tamano_buffer.py:

#!/usr/bin/env python

import socket
TAM_BUFFER_ENVIO = 4096
TAM_BUFFER_RECEPCION = 4096
def manipular_buffer():
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM )

# Get the size of the socket's send buffer
tamanoBuffer = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
print "Tamano Buffer [Antes]:%d" %tamanoBuffer

sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, 1)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_SNDBUF,TAM_BUFFER_ENVIO)
sock.setsockopt(socket.SOL_SOCKET,socket.SO_RCVBUF,TAM_BUFFER_RECEPCION)

tamanoBuffer = sock.getsockopt(socket.SOL_SOCKET, socket.SO_SNDBUF)
print "Tamano Buffer [Despues]:%d" %tamanoBuffer

if __name__ == '__main__':
manipular_buffer()

Una vez que hemos escrito nuestro programa, vamos a proceder a ejecutarlo en consola y veremos que obtenemos los valores del buffer antes y después de modificar su tamaño.

manipulacion-sockets-python2.jpg


El manejo de errores


Como con todo tipo de programas, al trabajar con sockets no estamos exentos de encontrarnos con algunos errores, el tema que debemos evitar es que estos errores nos tomen por sorpresa, ya que si lo hacen nuestra aplicación puede funcionar de forma impredecible.

Es por ello que debemos aprender a manejar los errores, de esta forma si ocurre una situación inesperada nuestro programa no muere si no que nos avisa que algo ha ocurrido, con ello evitaremos que haya corrupción de datos o situaciones similares que afectan la estabilidad de nuestra programa.

¿Cómo manejarlo?
Esto lo logramos utilizando bloques try – except que nos permiten evaluar situaciones, generalmente que involucran datos fuera de nuestro control y con ello podemos actuar en escenarios según las respuestas que obtengamos. Si llegamos a caer en la sección except del bloque podemos utilizar la propiedad error de nuestra instancia y con ello imprimir que ha ocurrido y así saber cuál fue la falla.


Haciendo un programa que maneje los errores


En el siguiente programa vamos a poner a prueba lo que hemos definido durante la explicación. En primer lugar vamos a crear un bloque que nos controle si la creación del socket ha tenido un error o no, con ello podremos asegurar un buen inicio de nuestro código.

Acto seguido vamos a evaluar la conexión de nuestra aplicación a un host remoto a través de un puerto en particular y con el manejo de errores podemos definir un mensaje personalizado. Finalmente hacemos el llamado a nuestra función y con ello ejecutaremos las acciones descritas.

Veamos el siguiente código que debemos almacenar en un archivo llamado errores_socket.py y luego lo ejecutaremos en consola:

#!/usr/bin/env python

import sys
import socket

host = 'http://python.orgt'
puerto = '06'

def manejo_errores():
		
		 try:
					 s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
		 except socket.error, e:
					 print "Hubo un error al crear el socket: %s" % e
	 sys.exit(1)
		 try:
					 s.connect((host, puerto))
		 except socket.gaierror, e:
					 print "Error en la direccion de conexion: %s" % e
					 sys.exit(1)
		 except socket.error, e:
					 print "Error de conexion: %s" % e
	 sys.exit(1)

if __name__ == '__main__':
manejo_errores()

Aquí vemos que hemos utilizado la librería sys para poder utilizar el método exit() y cerrar el programa luego que ocurra un error. También notamos que el host está incorrecto esto es para que podamos forzar al error y así ver el mensaje en pantalla. Por último notamos que utilizamos la variable e para capturar el error del socket, con ello podremos obtener el detalle real de lo que ocurrió.

Recordar
Aquí debemos tener especial cuidado con la indentación del código recordemos que Python al no utilizar llaves, también puntos y coma para definir los cierre de bloques depende exclusivamente de los espacios o tabulaciones que empleemos, por lo que si no lo hacemos correctamente veremos errores de sintaxis.


Es muy importante que leamos la documentación de la librería socket de Python para poder encontrar más y mejores formas de aprovechar sus recursos.

Con esto finalizamos este tutorial, nos hemos dado cuenta como Python tiene herramientas muy sencillas de entender que nos dan acceso al mundo de los sockets, con ello podremos empezar a programar aplicaciones que utilicen las redes para hacer procesamientos en tiempo real, como por ejemplo obtener información de otras máquinas de la red o incluso de Internet.

¿Te ayudó este Tutorial?


Sin comentarios, sé el primero!

No esperes más y entra en Solvetic
Deja tus comentarios y aprovecha las ventajas de la cuenta de usuario ¡Únete!

X