Programación de Socket en Python - PARTE - 1
Programación de Socket en Python - PARTE - 1
(Guía)
Table of Contents
• Background
• Socket API Overview
• TCP Sockets
• Echo Client and Server
o Echo Server
o Echo Client
o Running the Echo Client and Server
o Viewing Socket State
• Communication Breakdown
• Handling Multiple Connections
• Multi-Connection Client and Server
o Multi-Connection Server
o Multi-Connection Client
o Running the Multi-Connection Client and Server
• Application Client and Server
o Application Protocol Header
o Sending an Application Message
o Application Message Class
o Running the Application Client and Server
• Troubleshooting
o ping
o netstat
o Windows
o Wireshark
• Reference
o Python Documentation
o Errors
o Socket Address Families
o Using Hostnames
o Blocking Calls
o Closing Connections
o Byte Endianness
• Conclusión
Los sockets y la API de socket se utilizan para enviar mensajes a través de
una red. Proporcionan una forma de comunicación entre procesos
(IPC) . La red puede ser una red local lógica para la computadora, o una que
esté conectada físicamente a una red externa, con sus propias conexiones a
otras redes. El ejemplo obvio es Internet, a la que se conecta a través de su
ISP.
Las redes y los sockets son temas importantes. Se han escrito volúmenes
literales sobre ellos. Si es nuevo en los sockets o en las redes, es
completamente normal que se sienta abrumado con todos los términos y
piezas. ¡Sé que lo hice!
¡Empecemos!
Background
Los sockets tienen una larga historia. Su uso se originó con ARPANET en
1971 y luego se convirtió en una API en el sistema operativo Berkeley
Software Distribution (BSD) lanzado en 1983 llamado Berkeley sockets .
• socket()
• bind()
• listen()
• accept()
• connect()
• connect_ex()
• send()
• recv()
• close()
TCP Sockets
Como verá en breve, crearemos un objeto de socket
usando socket.socket()y especificaremos el tipo de socket
como socket.SOCK_STREAM. Cuando lo hace, el protocolo predeterminado
que se utiliza es el Protocolo de control de transmisión (TCP) . Este es un
buen valor predeterminado y probablemente sea lo que desea.
¿Por qué debería utilizar TCP? El Protocolo de control de transmisión (TCP):
• socket()
• bind()
• listen()
• accept()
Un socket de escucha hace exactamente lo que parece. Escucha las
conexiones de los clientes. Cuando un cliente se conecta, el servidor
llama accept()para aceptar o completar la conexión.
Servidor de eco
#!/usr/bin/env python3
import socket
bind() se utiliza para asociar el socket con una interfaz de red y un número
de puerto específicos:
# ...
s.bind((HOST, PORT))
Los valores pasados bind()dependen de la familia de direcciones del
socket. En este ejemplo, estamos usando socket.AF_INET (IPv4). Por lo que
espera una 2-tupla: (host, port).
host puede ser un nombre de host, una dirección IP o una cadena vacía. Si
se utiliza una dirección IP, host debe ser una cadena de direcciones con
formato IPv4. La dirección IP 127.0.0.1 es la dirección IPv4 estándar para
la interfaz de bucle invertido , por lo que solo los procesos del host podrán
conectarse al servidor. Si pasa una cadena vacía, el servidor aceptará
conexiones en todas las interfaces IPv4 disponibles.
Aquí hay una nota sobre el uso de nombres de host con bind():
Podría ser cualquier cosa. La primera vez que ejecute su aplicación, podría
ser la dirección 10.1.2.3. La próxima vez que se trata de una dirección
diferente, 192.168.0.1. La tercera vez, podría ser 172.16.7.8, y así
sucesivamente.
s.listen()
conn, addr = s.accept()
listen() tiene un backlog parámetro. Especifica el número de conexiones
no aceptadas que permitirá el sistema antes de rechazar nuevas
conexiones. A partir de Python 3.5, es opcional. Si no se especifica, backlog
se elige un valor predeterminado .
#!/usr/bin/env python3
import socket
print('Received', repr(data))
$ ./echo-server.py LINUX/MAC
> python echo-server.py WINDOWS CMD
$ ./echo-client.py LINUX/MAC
Received b'Hello, world'
$ ./echo-server.py
Connected by ('127.0.0.1', 64623)
Para ver el estado actual de los sockets en su host, use netstat. Está
disponible de forma predeterminada en macOS, Linux y Windows.
$ netstat -an
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 127.0.0.1.65432 *.* LISTEN
$ netstat -an
Active Internet connections (including servers)
Proto Recv-Q Send-Q Local Address Foreign Address (state)
tcp4 0 0 *.65432 *.* LISTEN
Local Address es *.65432, lo que significa que todas las interfaces de host
disponibles que admiten la familia de direcciones se utilizarán para aceptar
conexiones entrantes. En este ejemplo, en la llamada a socket(),
socket.AF_INET se utilizó (IPv4). Esto se puede ver en la
columna Proto: tcp4.
$ lsof -i -n
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
Python 67982 nathan 3u IPv4 0xecf272 0t0 TCP *:65432 (LISTEN)
Aquí hay un error común que verá cuando se realiza un intento de conexión
a un puerto sin conector de escucha:
$ ./echo-client.py
Traceback (most recent call last):
File "./echo-client.py", line 9, in <module>
s.connect((HOST, PORT))
ConnectionRefusedError: [Errno 61] Connection refused
Fallo de comunicación
Echemos un vistazo más de cerca a cómo el cliente y el servidor se
comunicaron entre sí:
Cuando se utiliza la interfaz de bucle invertido (dirección
IPv4 127.0.0.1o dirección IPv6 ::1), los datos nunca abandonan el host ni
tocan la red externa. En el diagrama anterior, la interfaz de loopback está
contenida dentro del host. Esto representa la naturaleza interna de la
interfaz de bucle invertido y que las conexiones y los datos que la transitan
son locales para el host. Esta es la razón por la que también escuchará la
interfaz de bucle invertido y la dirección IP 127.0.0.1o se le ::1
denominará "localhost".
Cuando usa una dirección IP que no sea 127.0.0.1o ::1en sus aplicaciones,
probablemente esté vinculada a una interfaz Ethernet que esté conectada
a una red externa. Esta es su puerta de entrada a otros hosts fuera de su
reino "localhost":
#!/usr/bin/env python3
import socket
HOST = 'localhost'
PORT = 65400
buffersize = 4096
s_sock.bind((HOST,PORT))
while True:
s_sock.sendto(data, addr)
#!/usr/bin/env python3
import socket
HOST = 'localhost'
PORT = 65400
buffersize = 4096