Underc0de

Programación Scripting => Python => Mensaje iniciado por: Sajuuk en Mayo 22, 2015, 05:28:40 AM

Título: [Mini-Guia] Sockets en Python (3.4)
Publicado por: Sajuuk en Mayo 22, 2015, 05:28:40 AM


(http://i61.tinypic.com/wt86ty.jpg)



La wikipedia nos dice:
CitarSocket designa un concepto abstracto por el cual dos programas (posiblemente situados en computadoras distintas) pueden intercambiar cualquier flujo de datos, generalmente de manera fiable y ordenada.

Yo lo veo más como un vehiculo, por el que se transportan datos desde el punto A (cliente) al punto B (servidor), e incluso también del punto B (servidor) al punto A (cliente). Nuestro vehículo está hecho de 2 piezas fundamentales: Dirección IP, y Puerto. Por ultimo, necesitan de aceite (flujo de datos), gasolina (conexión), y tener licencia de conducir (conexión fiable [ahorita lo explico]).



Un socket está compuesto por 2 cosas:

Yo me dedicaré a explicar el protocolo TCP/IP, ya que es el más utilizado (y el único que he manejado xD).



Pues bien, el protocolo TCP/IP nos garantiza 3 cosas:

Lo cual no ocurre en la alternativa de protocolo: UDP (User Datagram Protocol).
UDP solo nos garantiza que el mensaje llegue a su destino, sin importar si fué el primero en ser enviado o no, dandole más importancia al mensaje. Parece algo despistado, pero no lo es. UDP es usado en el streaming de audio (ya que la información es lo más importante).



Representación gráfica de un intento de conexión con TCP/IP:

(http://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Tcp-handshake.svg/376px-Tcp-handshake.svg.png)

No me detendré a explicar a fondo los segmentos SYN, y ACK, pero los "tantearé"

Esto tiene un nombre: three-way handshake.
¿Por que? Porque son 3 pasos para poder establecer conexión cliente-servidor.




Creando un socket en Python
[SERVER]



En Python, contamos con una librería que contiene las clases y funciones para manejar un socket. La librería se llama socket:

Comenzamos importandola:
Código (python) [Seleccionar]

import socket


Bien, ahora, necesitamos crear un socket.
Para esto, necesitamos una variable que sirva como un socket:
Código (python) [Seleccionar]

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


Bien, dentro de la librería, hay una clase llamada socket. En ella, nosotros seleccionaremos los parametros para crear un socket bajo el protocolo TCP/IP.
"socket.AF_INET, socket.SOCK_STREAM" son los parametros que nos crearán un objeto socket TCP/IP.

Los tipos de sockets en Python son los siguientes:



Ahora, necesitamos una IP, y un puerto.
Para esto, contamos con el método bind. Este método nos permite designarle una IP y un puerto a nuestro socket, ya que por obvias razones, no podemos crear un socket bajo TCP sin una IP y un puerto. Es como andar por ahí sin tener un nombre y una cuenta en underc0de.
Código (python) [Seleccionar]

mi_socket.bind(("127.0.0.1", 9999))


bind toma una tupla con los datos a designar.
A nuestro objeto socket le hemos designado la IP 127.0.0.1 (Esta IP es especial, ya que es usada como una alternativa al localhost, es decir, usaremos una IP local, en lugar de una pública [la que usa nuestra computadora para Internet (Facebook, Google, underc0de, etc...]).
También, le hemos designado un puerto: 9999.

Es importante saber que es recomendable usar un puerto bastante alejado de los puertos 21, 22, 80 ... etc, ya que estos son puertos especiales que nuestro Sistema Operativo usa para comunicarse por Internet y por red local. Así que trata de seleccionar un puerto más alla de... 5000?



Bien, ahora, especificaremos cuantas "orejas" tendrá nuestro socket:
Código (python) [Seleccionar]
mi_socket.listen(5)

Digo orejas porque, cada oreja estará escuchando a través del puerto que seleccionamos, esperando a que una conexión de un cliente llegue.
Al nosotros colocar un 5 entre los paréntesis, le estamos diciendo a nuestro socket que estamos esperando 5 posibles clientes.

Si llegamos a tener 5 clientes conectados, automáticamente no permitirá otro más.



Entonces, de repente llega una conexión, y nuestro servidor tiene que tomarla.
¿Qué metodo utilizaremos?
Código (python) [Seleccionar]

sc, addr = mi_socket.accept()



El método accept() espera una conexión. Cuando llega, este acepta la conexión, y procedemos a la parte que todos queremos.



Necesitamos recibir los datos que nuestro cliente nos está enviando.
Para esto, socket cuenta con un método llamado recv():
Código (python) [Seleccionar]

recibido = sc.recv(1024)


La variable recibido contendrá lo que el cliente envie hacia nosotros.

Bien, lo que está entre paréntesis es el limite de bytes que se esperan como respuesta. Si se excede el límite, no se recibe ni se acepta el resto del mensaje, dejandolo "mocho" (o cortado).



Ahora, ya tenemos lo que el cliente nos está diciendo, pero, ¿cómo le respondo?
Entonces, el método send() llega para salvarnos:
Código (python) [Seleccionar]

nuestra_respuesta = "Hola cliente, yo soy el servidor. Unete a underc0de!"
sc.send(nuestra_respuesta.encode('utf-8'))


El método send() envía una respuesta (texto u otros datos) al cliente.

Usamos la variable sc (cliente) para enviarle un mensaje.
Luego, antes de enviarle el mensaje, necesitamos codificarlo bajo algún estandar.
Generalmente usamos "utf-8" (Español, con esto, podemos enviar caracteres especiales como la ñ).

Entonces, tomamos nuestro mensaje, y seguido de un punto ( . ) escribimos encode, seguido de parentesis y el tipo de codificación a usar.



Entonces, cuando terminemos nuestro trabajo, necesitaremos cerrar nuestro objeto socket cliente, y también cerrar nuestro socket servidor;
Código (python) [Seleccionar]

sc.close()
mi_socket.close()


El método close() detiene y elimina los socket creados.


Código completo:
Código (python) [Seleccionar]

import socket
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.bind(("127.0.0.1", 9999))
s.listen(5)

print ("Servidor de Chat\n")

while True:
print ("Esperando conexión...")
sc, addr = s.accept()
print ("Cliente conectado desde: ", addr)

while True:
recibido = sc.recv(1024)
if recibido == "quit":
break
print ("Recibido: ", recibido)

nuestra_respuesta = "Hola cliente, yo soy el servidor. Unete a underc0de!"
sc.send(nuestra_respuesta.encode('utf-8'))

print ("Adios")
sc.close()
s.close()


OJO: Usamos "while True" para mantener el socket abierto, incluso si ya enviamos una respuesta. Esto evitará que se cierre, y no podamos seguir enviando/recibiendo información.

Y LISTO. Creamos un socket bajo el protocolo TCP/IP (el más usado en la Internet de este planeta y en Andromeda).




Creando un socket en Python
[CLIENTE]



Crear un socket cliente es un poco más fácil, ya que nos ahorramos unas cuantas lineas de código.

Para esto, importamos la libreria socket, y creamos el socket cliente:
Código (python) [Seleccionar]

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


Bien, ahora, no necesitamos ni bind, ni listen, ni nada.
Tan solo ocupamos un método: connect()
Código (python) [Seleccionar]

socket_cliente.connect(("127.0.0.1", 9999))


El método connect() toma la tupla con los datos: IP a conectarse, y el puerto donde está escuchando el servidor.



Ahora, ya establecimos una conexión con el servidor, entonces ya podemos enviar mensajes.
Volvemos a usar el método send()
Código (python) [Seleccionar]

while True:
mensaje = "Hola, soy el cliente, y ya me uní a underc0de!"

socket_cliente.send(mensaje.encode("utf-8"))


Usamos nuestro objeto cliente para enviarlo.
Volvemos a codificar el mensaje en utf-8, para poder incluir caracteres que en el idimoa inglés no hay.



Entonces, nosotros querremos recibir las respuestas del servidor. Para esto, volvemos a recv()
Código (python) [Seleccionar]

recibido = socket_cliente.recv(1024)
print("Recibido: ", recibido)


El socket cliente estará esperando un máximo de 1024 bytes como respuesta.
Imprimimos lo que el servidor nos envió.



Y por ultimo, para terminar el programa cerramos el socket cliente:
Código (python) [Seleccionar]

socket_cliente.close()



Código completo:
Código (python) [Seleccionar]

import socket

socket_cliente = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket_cliente.connect(("localhost", 5000))

while True:
mensaje = str(input(">> "))
socket_cliente.send(mensaje.encode('utf-8'))

recibido = socket_cliente.recv(1024)
print("Recibido: ", recibido)

print ("Adios")
socket_cliente.close()





Creando un pequeño Port Scanner



Un Port Scanner (o escaner de puertos) se conectará a una ip, y a un rango determinado de puertos, con la finalidad de descubrir puertos abiertos por donde un tercero puede atacar un sistema.

Código (python) [Seleccionar]

# Coded by Barlan. 2015
import socket
import sys

if len(sys.argv) != 4:
print("[!] Use: scan.py [IP_to_scan] [Initial_Port] [Final_Port]")
sys.exit(1)

def connect(IP, port):
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
socket.setdefaulttimeout(0.6)
try:
s.connect((IP, port))
return(1)
except:
return(2)

IP = str(sys.argv[1])
ip = int(sys.argv[2])
fp = int(sys.argv[3])
print("[*] Connecting to %s, scanning from %s to %s ..." % (IP, ip, fp))

for port in range(ip, fp+1):
e = connect(IP, port)
if e == 2:
print("[-] %s closed." % port)
else:
print("[+] %s open." % port)

print("Finished!")


Bien, importamos la librería sys para usar argumentos.



Entonces nos vamos a la función connect.
Esta función espera una IP y un puerto.
Entonces en ella creamos un socket cliente.

(El método setdefaulttimeout() sirve para declarar cuantos segundos podemos esperar a que el servidor nos conteste. Esto es útil cuando no queremos esperar mucho por una conexión. SI te pones a pensar, esto es lo que usan en los videojuegos para evitar tener a un jugador ocupando un espacio)

Llegamos al bloque try/except.
Enviamos una solicitud de conexión a la IP.
SI la conexión fué exitosa (osea, que el puerto está abierto), retorna un valor 1.

En caso contrario (que el puerto esté cerrado) retorna un valor 2.



Entonces, salimos de la función y nos vamos a la linea 23:
Código (python) [Seleccionar]

for port in range(ip, fp+1):
e = connect(IP, port)
if e == 2:
print("[-] %s closed." % port)
else:
print("[+] %s open." % port)


Por cada numero dentro del rango del puerto inicial hasta el final, ejecutar la función connect (pasandole una IP, y un puerto).
Si la función retorna un valor 1, entonces nos imprime el puerto que está abierto.

Pero si nos retorna un valor 2, entonces nos imprime el puerto que está cerrado.




Si creen que pueda añadirse más contenido favor de reportarmelo.  :)

Te ha hablado Barlan y te deseo... buenas noches.
Título: Re:[Mini-Guia] Sockets en Python (3.4)
Publicado por: Lovecraft en Junio 02, 2016, 12:59:43 AM
al fin entiendo esta webonada xD ,gracias
Título: Re:[Mini-Guia] Sockets en Python (3.4)
Publicado por: tincopasan en Junio 02, 2016, 04:20:12 AM
Gracias, está muy bien detallado, ahora ya que hablás de comunicación entre dos máquinas, podrías agregar como enviar "ping"  en un segmento de red para saber si la máquina está inactiva o no!
Saludos y muy buen trabajo.
Título: Re:[Mini-Guia] Sockets en Python (3.4)
Publicado por: burpsuite en Diciembre 16, 2017, 03:41:51 PM
Cuando introduces 'quit' no sale del bucle while. He visto el codigo varias veces y a mi parecer esta todo correcto, lo que no entiendo es porque el break no rompe el bucle y se imprime 'Adios'
Título: Re:[Mini-Guia] Sockets en Python (3.4)
Publicado por: hell0h0la en Abril 23, 2018, 01:17:46 AM
Por fin entiendo los sockets gracias

Enviado desde mi GT-I8190N mediante Tapatalk