Tutorial de sockets en Python.
Autor. Juan Francisco Benavides Nanni
Contacto. elnanni@gmail.com
Pagina. Make Me a BlogJob.
Fecha. 17/02/2006
Nivel. Intermedio.


Y que es lo grandioso de los sockets??


Para todos aquellos que estan comenzando a desesperarse porque no hemos hecho aplicaciones utiles, pues ahora vamos a realizar un tipo de chat, no es muy estetico, pero es un comienzo.

# servchat.py # Creamos un servidor de chat. # Juan Francisco Benavides Nanni - Dracko - 17/02/2006
import socket import select def accept_new_connection(): try: global server global desc newsock, (remhost, remport) = server.accept() server.settimeout(.1) print "Se ha conectado %s:%s" % (str(remhost), str(remport)) desc.append(newsock) except: pass def broadcast(msg, sock): global desc global server host, port = sock.getpeername() msg = "[%s:%s]: %s" % (str(host), str(port), str(msg)) for destsock in desc: if destsock != sock and destsock != server: destsock.send(msg) def get_msg(sock): try: msg = sock.recv(1024) sock.settimeout(.1) return msg except: global desc host, port = sock.getpeername() print "[%s:%s] ha salido." % (str(host), str(port)) desc.remove(sock) return None global server server = socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.bind(("", 8000)) server.listen(5) global desc desc = [server] while 1: accept_new_connection() (sread, swrite, sexc) = select.select(desc, [], []) for sock in sread: if sock != server: flag = get_msg(sock) if flag: broadcast(flag, sock)
Bajar codigo.


Pues a mi parecer esto se puso interesante, como se acaban de dar cuenta hemos dado un gran paso, de unos simples Scripts que solo aceptaban conexiones y mandaban un mensaje, dimos un giro al realizar una aplicacion que maneje "usuarios" y los comunique, la verdad es que esa no es la unica manera de hacer un servidor de chat, bueno la base de uno, hay infinidad de maneras, talvez esta incluso sea una pesima manera de realizarlo, pero funciona para nuestros propositos de este tutorial.
Muy bien, a la explicación:

# servchat.py # Creamos un servidor de chat. # Juan Francisco Benavides Nanni - Dracko - 17/02/2006
import socket import select
Lo unico diferente aqui es que ahora incluimos el modulo de select, no se preocupen, será explicado en su debido momento.

global server
server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.bind(("", 8000))
server.listen(5)
global desc
desc = [server]
while 1:
    accept_new_connection()
    (sread, swrite, sexc) = select.select(desc, [], [])
    for sock in sread:
        if sock != server:
            flag = get_msg(sock)
            if flag:
                broadcast(flag, sock)
        
Despues pasamos a las funciones, primero hay que entender lo que se espera realizar, muy bien, estamos creando variables globales (global), para que estas puedan ser modificadas en las funciones, despues creamos el servidor, asignandole una direccion y un puerto, despues hacemos el ciclo infinito el cual ya fue explicado, y ya adentro de ese ciclo aceptamos nuevas conexiones (accept_new_connection()), ahora sigue lo del select, como pueden ver le estamos mandando una lista donde se encuentran los sockets que se estan usando (incluyendo el server) lo unico que nos importa es saber cuando un socket se intenta comunicar con el servidor, es por eso que los otros dos parametros los dejamos vacios (select.select(desc, [], [])), el select nos devolvera los que se intentan comunicar, despues verificamos cada elemento que nos fue regresado (excluyendo al server (if sock != server:)) para saber que es lo que intenta hacer, despues recivimos el mensaje de cada socket que se comunicó (get_msg()) y lo mandamos a todos (broadcast()), dentro de la función de get_msg() también verifica que siga conectado ese cliente.

def accept_new_connection():

    try:
        global server
        global desc
        newsock, (remhost, remport) = server.accept()
        server.settimeout(.1)
        print "Se ha conectado %s:%s" % (str(remhost), str(remport))
        desc.append(newsock)
    except:
        pass
        
Lo que esta haciendo esta función es utilizar las variables globales, para poderlas modificar, entonces lo que intenta es recivir una nueva conexion, pero solo lo hace por un periodo corto de tiempo (server.settimeout(.1)), si ese tiempo se acaba se pasa a la esepción la cual no hace nada, pero si en ese tiempo llega una nueva conexion entonces la acepta y guarda el nuevo socket en la lista (desc.append(newsock)).

def get_msg(sock):

    try:
        msg = sock.recv(1024)
        sock.settimeout(.1)
        return msg
    except:
        global desc
        host, port = sock.getpeername()
        print "[%s:%s] ha salido." % (str(host), str(port))
        desc.remove(sock)
        return None
        
En esta función intentamos recivir un mensaje (msg = sock.recv(1024)) del socket que pasamos como parametro, pero una véz más le dejamos un tiempo limite, si ese tiempo es excedido significa que el cliente se ha desconectado y lo quitamos de la lista, y devolvemos None, para que no entre a la condicional que tenemos en el programa principal.
Pero si nos manda un mensaje lo regresamos para que entre a la codicional en el programa principal, y ahi sera llamada la siguiente función:

def broadcast(msg, sock):

    global desc
    global server
    host, port = sock.getpeername()
    msg = "[%s:%s]: %s" % (str(host), str(port), str(msg))
    for destsock in desc:
        if destsock != sock and destsock != server:
            destsock.send(msg)
        
lo que realiza esta función es utilizar las variables globales para asi mandar un "broadcast", el mensaje que recive como parametro es lo que mandara a todos.

Se verá algo como esto:

Comunicacion!!.





Anterior. Siguiente.