miércoles, 13 de enero de 2010

Sockets en Python

Untitled Document.md

Introduccion a los sockets

programar en red con python puede caer en 2 categorias, usar un modulo de
protocolo o programar el protocolo desde cero.
los sockets son una extension del sistema de entrada/salida del sistema
operativo que permite la comunicacion entre procesos y maquinas.
un socket permite usar llamadas del sistema operativo para hablar con otras
maquinas y/o procesos sobre la maquina que los ha llamado.

algunas llamadas al sistema en *nix que funcionan con descriptores de ficheros
incluyen a open(), read(), write(), close(). un descriptor de fichero
tipicamente refiere a un fichero o una entidad de tipo fichero; pueden ser,
directorios, bloques, socket, fifo’s.

python provee una interface de socket del sistema operativo, el modulo socket,
si es que se piensa diseñar el protocolo desde cero.

Creación de un socket

la creación de un socket es diferente de un cliente a un server.

creación de un cliente

primero, se tiene que crear el objeto socket, luego se le tiene que definir la
familia del protocolo (como será transmitida la data), y el tipo desocket
(protocolo usado para transmitir la data).

familias de procolo: socket.AF_UNIX, socket.AF_INET, socket.AF_INET6
Tipo de socket: socket.SOCK_STREAM, socket.SOCK_DGRAM, socket.SOCK_RAW,
socket.SOCK_RDM, socket.SOCK_SEQPACKET

Segundo, hay que conectar el objeto socket al servidor remoto. El método connect()
envia una tupla conteniendo el host remoto | dirección IP y el puerto remoto.

    host = "www.example.com"
    port = 80
    #Creación del objeto socket
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)#Conectandolo hacia un host remoto
    s.connect(host, port)

Creación de un server

La creación de un server es parecido al de un cliente. Primero se tiene que
crear el objeto socket, luego añadir las opciones de socket setsockopt();
además, se tiene que asociar un puerto a una interface de red y ponerlo a
escuchar por conexiones. Finalmente, se aceptan las conexion de los clientes
usando socket.accept() en una iteración infinita hasta que el programa
termine o levante una excepción. Los servers usan la misma interface socket que
los clientes.

    host = ' '
    port = 9876

    #Creacion del objeto 
    s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    #Definir las opciones del socket
    s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

    #Asociarlo a un puerto + interface
    s.bind(host, port)

    #Ponerlo a escuchar por conexiones
    s.listen(3)

Comunicando con sockets

Python provee 2 maneras para enviar data a través de la red: objetos de socket,
y objetos tipo fichero usando socket.makefile().

Los objetos de socket se usan cuando hay una necesidad de controlar el tamaño,
los tiempo de espera, u algun otro detalle de la data que esta siendo escrita o leida.

Los objetos de fichero son mejores si se trabaja con protocolos orientados a
conexión ya que pueden manejar el análisis sintáctico de la data recibida que
ha sido garantizada por el protocolo.

Errores en la transmisión pueden ocurrir por varios factores tales como, la
desconexión de un servidor, error de direccionamiento, etc.
Por ello python define 4 posibles excepciones:

  • socket.error para problemas generales de entrada/salida

  • socket.gaierror para error de búsqueda de información de direccionamiento.

  • socket.herror para errores de direccionamiento para funciones que usan h_errno en C.

  • socket.timeout para manejar tiempo de espera después de haber llamado settimeout() sobre un socket.

Los errores con los objetos tipo ficheros en realidad hacen una llamada al
socket del sistema, asi que se aplican los mismos errores que los objetos de
socket. También se debe evitar el bloqueo mutuo entre el emisor y el receptor,
por ello hay que asegurar envio/recibo de data con socket.shutdown() antes de
recibir/enviar nueva data.

Sobre tiempos de espera para detectar y manejar errores es utilizando timeouts,
con esto se puede conseguir que python detecte inactividad en el sistema cuando
hay comunicación entre el cliente y el servidor. Para habilitar timeouts,
llamamos a socket.settimeout() enviando el tiempo limite en segundos, luego
si existe un problema de tiempo de espera se llamará socket.timeout como excepción.

También se pueden realizar transmisiones de un solo sentido usando llamadas a
socket.shutdown(), con esto logramos sockets de una sola via (half open sockets).
Esto es útil si se requiere asegurar que toda la data escrita ha sido
transmitida, o preveer deadlocks en una comunicación. Al finalizar el llamado a
shutdown y asegurar que toda la data ha sido transmitida en esa via, el
socket no podrá ser usado nuevamente.

La llamada a socket.shutdown() requiere un argumento para indicar el modo de
funcionamiento o modo de bloqueo.

  • 0 previene lecturas.

  • 1 previene escrituras.

  • 2 previene lecturas y escrituras.

CODIGO DE EJEMPLO:

El siguiente ejemplo lo he realizado orientado a conexión y sin conexión, en
ambos el servidor recibe como parámetro un fichero del arbol *nix para ser
listado y enviado al cliente; para ejecutar el fichero sera necesario 2 consolas
abiertas o el servidor corriendo en 2do plano.

    #./[script] [fichero]
    #./serverTCP.py
    #./clienteTCP.py /etc/

Clientes con python

  • Cliente TCP

#!/usr/bin/python

#Cliente objeto socket

    import socket, sys
    host = "127.0.0.1"
    port = 10101
    filename = sys.argv[1]

    #Creacion del objeto socket (IPv4, TCP)
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    except socket.error, e:
        print "Error creando el socket: %s" %e

    #Conectandolo hacia un host remoto
    try:
        s.connect((host, port))
    except socket.gaierror, e:
        print "Error conectando al servidor %s" %e
    try:
        s.sendall(filename)
    except socket.error, e:
        print "Error enviando datos: %s" %e
    while 1:
        try:
            buf = s.recv(2048)
        except socket.error, e:
            print "Error reciviendo datos: %s" %e
        if not len(buf):
            break
        sys.stdout.write(buf)
  • Cliente UDP
    #!/usr/bin/python
    import socket, sys
    host="127.0.0.1"
    port=10101
    message=sys.argv[1]
    try:
        s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    except socket.error, e:
        print "Error creando el socket: %s:" %e
    try:
        s.sendto(message,(host,port))
    except socket.error, e:
        print "Error enviando datos: %s" %e
    s.settimeout(5)
    while 1:
        try:
            message, address=s.recvfrom(2048)
        except socket.timeout:
            print "Cerrado por inactividad"
            sys.exit(1)
        except socket.error, e:
            print "Error recibiendo datos: %s" %e
        if not len(message):
            break
        sys.stdout.write(message+"\n")

Servers con python

  • Server TCP

      #!/usr/bin/python 
      import socket, pickle, os 
      host = "" 
      port = 10101 
    
      #Creacion del objeto socket(IPv4, TCP) 
      s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    
      #Definir las opciones del socket 
      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    
      #Asociarlo a un puerto + interface 
      s.bind((host, port)) 
    
      #Ponerlo a escuchar por conexiones 
      s.listen(3) 
      print "Corriendo sobre puerto %d; Ctrl-C para interrumpir" % port
      while 1: 
          try: 
              csock, caddr = s.accept() 
          except KeyboadInterrupt: 
              raise 
          except: 
              traceback.print_exc() 
      continue 
    
      #Manejando la conexion 
      try: 
          print "Cliente conectado", csock.getpeername()
      except KeyboadInterrupt:
          raise
      except:
          traceback.print_exc()
      while 1:
          try:
              data = csock.recv(2048)
              if not len(data):
                  break
              dir=os.listdir(data)
              for dir in dir:
                  csock.sendall(dir+"\n")
                  csock.shutdown(1)
          except KeyboadInterrupt:
              raise
          except:
              traceback.print_exc()
              csock.close()
    
  • Server UDP

      #ServerUDP.py
      #!/usr/bin/python
    
      import socket, os
      host=""
      port=10101
      s=socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
      s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
      s.bind((host,port))
      print "Corriendo sobre puerto %d; Ctrl-C para interrumpir" % port
      while 1:
          try:
              message, address = s.recvfrom(2048)
              print "Got data from", address
              dir=os.listdir(message)
              for listdir in dir:
                  s.sendto(listdir, address)
          except KeyboardInterrupt:
              raise
          except:
              traceback.print_exc()
    

sábado, 24 de octubre de 2009

Algunas de Vi: Busqueda


Busqueda en vi

Key Función
fa Busca el primer caracter a desde la derecha del cursor.

Fa Busca el primer caracter a desde la izquierda del cursor.

; Repite el último f,F comando.

/string Busca por el string hacia la derecha del cursor, se pueden usar regexp

?string Busca por el string hcia la izquierda del cursor, se pueden usar regexp

n Repite el último comando / o ?.
set number Enumera todas las lineas.



viernes, 23 de octubre de 2009

Algunas de Vi: Copiar y Pegar

Copiar y Pegar

Key Función
yy or Y Copia una linea al buffer.
nyy or nY Copia n lineas al buffer.
yw Copia una palabra al buffer.

ynw or nyw Copia n palabras al buffer.
y$ Copia el texto desde el cursor hasta el final de la linea.

“ayy Copia una lina al buffer llamado a.

“Ayy Agrega una linea al buffer llamado A.

p Pega texto a la derecha del cursor.

P Pega texto a la izquierda del cursor.

np Pega n copias de texto a la derecha del cursor.

“ap Pega el contenido del buffer a hacia la derecha del cursor.

“c3P Pega 3 copias de texto del buffer c hacia la izquierda del cursor.

“add Mueve la linea al buffer llamado a.

“a5dd Mueve 5 lineas al buffer llamado a.

dw Elimina una palabra y la pone en el buffer.

Algunas de Vi: Eliminar

Eliminar con Vi

Key Función
x Elimina el caracter donde está el cursor.

X Elimina el caracter antes del cursor.

dw Elimina una palabra.

dd Elimina una linea.

D Elimina todo el texto después del cursor hasta el final de la linea.

dL Elimina todo el texto después del cursor hasta el final de la pantalla.

dG Elimina todo el texto desde el cursor hasta el final del archivo.

d^ Elimina todo el texto desde el inicio de la linea hasta el cursor.

d1g Elimina todo el texto desde el inicio del archivo hasta el cursor.

dn$ Elimina todo el texto desde el cursor hasta la linea n especificada.


Algunas de Vi: Añadir texto

Comandos para añadir texto
key     Función
i Inserta texto a la izquierda del cursor.

I Inserta texto antes del primer caracter sin espacio.

a Agrega texto a la derecha del cursor.

A Agrega texto al final de la linea.

o Empieza una nueva linea debajo de la linea actual.

O Empieza una nueva linea encima de la linea actual.


cw Cambia una palabra.
cs Cambiar una oración.

c$ or C Cambia la linea actual

r Reemplaza un caracter.

R Reemplaza texto hasta que la tecla ESC es presionada.

s Substituye texto por el caracter actual.

Algunas de Vi: Desplazamiento

Comando de desplazamiento del cursor


Key Función
h Mueve el cursor un caracter a la izquierda.
j Mueve el cursor una linea hacia abajo.
k Mueve el cursor una linea hacia arriba.
l Mueve el cursor un caracter a la derecha.
Ctrl-G Muestra la linea actual.
nG Ir hacia la linea especificada por n.
Ctrl-f Mueve hacia adelante una pantalla.
Ctrl-b Mueve hacia atrás una pantalla.
Ctrl-d Mueve hacia adelante media pantalla.
Ctrl-u Mueve hacia atrás media pantalla.
w Ir al principio de la siguiente palabra Moves to the start of the next word.
e Ir al fin de la siguiente palabra.
^ Ir a la primera palabra de la linea actual.
$ Ir al fin de la linea actual.
Enter Ir a la siguiente linea.
- Ir al principio de la linea anterior.
G Ir al final del archivo.
% Ir hasta el parantesis correspondiente.
H Ir a la primera linea de la pantalla.
M Ir a la mitad de la pantalla.
L Ir al final de la pantalla.
n| Mover el cursos a la columna n.

viernes, 2 de octubre de 2009

DNS + Gentoo 1.0

A fin de mantener un buen seguimiento de las actividades que estoy realizando con la compu que me regalaron, esta es la documentación del DNS para fines locales y de pruebas.
Primero que nada vamos a dar las especificaciones del servidor:
Procesador Intel P4 de 2.8Ghz
Memoria 256 ram
Disco duro de 20gb
2 interfaces de red

El software para implementar el DNS ha sido el omnipresente bind9, para instalarlo solo basta con hacerle un simple emerge. También se instaló el paquete bind-tools para tener las herramientas para depuración y busqueda de información de registros DNS (nslookup, host, dig).
#emerge bind bind-tools

Una vez que portage haya terminado con su trabajo, los archivos para configurar bind se encontrarán en /etc/bind/ y /var/bind/.
Ahora es momento de definir el esquema de red. En mi caso consta de 2 portatiles + 1 PC(servidor) conectadas a un router inalámbrico.
Para esto usaremos:

Dominio: bitclux
lap1: nuix 192.168.1.40
lap2: hyp 192.168.1.30
servidor: v00wix 192.168.1.254
router: router 192.168.1.1
admin: root
Red Local: 192.168.1.0

Configurando el archivo "/etc/named.conf"

#vi /etc/named.conf
options {
directory "/var/bind";
listen-on-v6 { none; };
listen-on { 127.0.0.1; 192.168.1.254; };
pid-file "/var/run/named/named.pid";
};

#Declaración option: define opciones de configuracion globales
#entre las opciones mas usadas tenemos:
#directory: Reemplaza al directorio actual /var/named, por otro directorio que se indique.
#listen-on: Para especificar la interfaz de red por la que named escuchara las solicitudes; por defecto, el servicio named escuchara por todas las interfaces.
#listen-on-v6: Soporte para direcciones IPv6.

zone "bitclux" {
type master;
file "pri/bitclux.zone";
allow-transfer { any; };
};

zone "." IN {
type hint;
file "named.ca";
};

zone "localhost" {
type master;
file "pri/localhost.zone";
allow-transfer { none; };
notify no;
};

zone "127.in-addr.arpa" IN {
type master;
file "pri/127.zone";
allow-update { none; };
notify no;
};

#zona: porcion discreta del espacio de nombres de dominio
#existen opciones:
#allow-transfer: indica a los servidores esclavos que estan autorizados a pedir transferencia zona.
#allow-update: indica a los hosts que estan autorizados a actualizar dinamicamente la informacion de la zona.
#file: nombre de archivo que contiene la información de la zona
#notify: controla si se notifica a los servidores esclavos.
#type: tipo de zona:
*hint: Para orientar hacia los servidores root para perticiones de nombres que no se conocen.
*master: Servidor con autorizacion de zona

Configuración de los registros de la zona "/var/bind/"
#vi /var/bind/bitclux.zone

$TTL 2d
@ IN SOA ns.bitclux. root.bitclux. (
20091001 //serial
3h //tiempo de refresco
1h //tiempo de reintentos
1w //tiempo de expiración
1d ) //ttl minimo

bitclux. IN NS ns.bitclux.
ns.bitclux. IN A 192.168.1.254
ns.bitclux. IN A 192.168.1.253
router.bitclux. IN A 192.168.1.1
nuix.bitclux. IN A 192.168.1.40
hyp.bitclux. IN A 192.168.1.30
v00wix.bitclux. IN A 192.168.1.254

# $TTL: Indica el tiempo en segundos que el servidor mantiene el registro en memoria.
# $ORIGIN: Anexa el nombre de dominio a registros no cualificados, como aquellos con el nombre de host solamente
# SOA: Ubicado detras de las directivas, es el primer registro de recursos, e indica la autorizacion de una zona al servidor DNS
#@: Coloca la directiva $ORIGIN, como el espacio de nombres que esta siendo definida para el registro SOA


Finalmente agregamos el bind al runlevel por defecto, agregamos la direccion del servidor en /etc/resolv.conf e iniciamos el bind:
#rc-update add named default
#echo -e "nameserver 192.168.1.254" >> /etc/resolv.conf
#/etc/init.d/named start

=D