[Python] Programación de red - Socket (1)

1. Resumen de enchufes

Socket, el significado original es "socket", en el campo de la comunicación informática, Socket generalmente se traduce como "socket". La definición de Socket de la Enciclopedia Baidu es la siguiente: "El llamado socket (Socket) es la abstracción de los puntos finales para la comunicación bidireccional entre procesos de aplicación en diferentes hosts en la red. Un socket es un extremo de la comunicación del proceso en la red , proporcionando Define el mecanismo para que el proceso de la capa de aplicación intercambie datos utilizando el protocolo de red. Desde la perspectiva de su posición, el socket está conectado al proceso de aplicación y conectado a la pila de protocolo de red. Es la interfaz para el programa de aplicación. para comunicarse a través del protocolo de red. La interfaz para interactuar con la pila" [1] .

¿Como entender? Para entender la definición de Socket en el párrafo anterior, necesitamos entender brevemente el protocolo TCP/IP. El protocolo TCP/IP, es decir, el Protocolo de control de transmisión/Protocolo de Internet (Protocolo de control de transmisión/Protocolo de Internet), se refiere a un grupo de protocolos que puede realizar la transmisión de información entre múltiples redes diferentes, y es un término general para una serie de comunicaciones de red. protocolos [2 ] . En términos sencillos, el protocolo TCP/IP es una descripción de las reglas que se deben seguir para la comunicación entre computadoras, solo siguiendo estas reglas las computadoras se pueden comunicar entre sí [3] . El protocolo TCP/IP adopta una estructura de 4 capas, que son la capa de aplicación, la capa de transporte, la capa de red y la capa de enlace, como se muestra en la Figura 1 a continuación [1] [ 4 ] :

inserte la descripción de la imagen aquí

Figura 1. Estructura del protocolo TCP/IP
 
  • Capa de aplicación: la capa de aplicación es responsable de manejar los detalles específicos de la aplicación. Los protocolos de la capa de aplicación incluyen principalmente Telnet, FTP, SMTP, etc.
  • Capa de transporte: La capa de transporte, también conocida como capa de transporte, es la principal responsable de proporcionar comunicación entre aplicaciones. Los protocolos de la capa de transporte incluyen principalmente TCP y User Datagram Protocol (User Datagram Protocol, UDP).
  • Capa de red: la capa de red también se conoce como capa de Internet y es la principal responsable de la comunicación entre las computadoras vecinas. Los protocolos de la capa de red incluyen principalmente IP, ICMP e IGMP.
  • Capa de enlace: la capa de enlace también se denomina capa de enlace de datos o capa de interfaz de red, que generalmente incluye el controlador del dispositivo en el sistema operativo y la tarjeta de interfaz de red correspondiente en la computadora. La capa de enlace es principalmente responsable de enviar y recibir datagramas IP para el módulo IP, enviar solicitudes ARP y recibir respuestas ARP para el módulo ARP, y enviar solicitudes RARP y recibir respuestas RARP para RARP. Los protocolos de la capa de enlace incluyen principalmente ARP y RARP.

Socket es la capa de abstracción de software entre la capa de aplicación y la capa de transporte, como se muestra en la Figura 2 a continuación. Socket es la encapsulación del protocolo TCP/IP [5] . Socket proporciona un conjunto de interfaces para que las aplicaciones interactúen con la pila de protocolos de red. A través de Socket, las aplicaciones pueden interactuar fácilmente con la pila de protocolos de red, de modo que diferentes aplicaciones puedan comunicarse.

inserte la descripción de la imagen aquí

Figura 2. La posición de Socket en el protocolo TCP/IP
 

Por lo tanto, podemos abstraer a Socket como punto final para la comunicación entre aplicaciones, como se muestra en la Figura 3 a continuación.

inserte la descripción de la imagen aquí

Figura 3. El zócalo es una abstracción de un punto final para la comunicación bidireccional entre procesos de aplicación en diferentes hosts en la red
 

Para entenderlo de forma más general, así como podemos obtener suministro eléctrico de la red conectando el enchufe a la toma de corriente, la aplicación necesita estar conectada a Internet antes de recibir o enviar datos, y Socket es una herramienta que se utiliza para conectar la aplicación a la toma de corriente. Internet [6] .

inserte la descripción de la imagen aquí
Las aplicaciones típicas de Socket son servidores web y navegadores: el navegador obtiene la URL ingresada por el usuario e inicia una solicitud al servidor; el servidor analiza la URL recibida y devuelve el contenido de la página web correspondiente al navegador; presenta elementos como texto, imágenes y vídeos para los usuarios [6] .


2. Creación de enchufes

En Python, usamos la función socket() para crear un socket, y su sintaxis es la siguiente (primero debe importar el módulo de socket) [7] :

socket.socket([family[, type[, proto]]])  # 使用给定的地址族、套接字类型及协议号来创建套接字

Descripción de parámetros [7] - [9] :

  • familia: familia de direcciones, este parámetro por defecto es socket.AF_INET.

inserte la descripción de la imagen aquí

  • type: tipo de socket, el parámetro predeterminado es socket.SOCK_STREAM.

inserte la descripción de la imagen aquí

  • protocolo: número de protocolo, generalmente predeterminado en 0, para que el sistema seleccione automáticamente el protocolo apropiado de acuerdo con la familia de direcciones y el tipo de socket.

3. Método incorporado del objeto Socket

En esta parte, solo presentamos algunos métodos importantes que usaremos a continuación. Para otros métodos, consulte el documento [10] .

método describir
método de servidor
socket.bind(dirección) Vincule el socket a la dirección de la dirección , el formato de la dirección depende de la familia de direcciones anterior. Para AF_INET, la dirección se expresa en forma de tupla (host, puerto).
socket.listen([retraso]) Permite que el servidor acepte conexiones, es decir, escuche conexiones. backlog especifica el número máximo de conexiones que el sistema puede suspender antes de rechazar la conexión. El valor debe ser al menos 0 y la mayoría de las aplicaciones deben establecerlo en 5.
socket.aceptar() Acepte la conexión. El socket primero debe vincularse a una dirección y escuchar las conexiones. Este método devuelve un par (conn, dirección), donde conn es un nuevo objeto Socket para enviar y recibir datos en la conexión; dirección es la dirección vinculada al Socket en el otro extremo de la conexión.
método de cliente
socket.connect(dirección) Conéctese al enchufe en la dirección . El formato de la dirección depende de la familia de direcciones mencionada anteriormente.
socket.connect_ex(dirección) Una versión extendida del método connect. La diferencia es que este método devolverá un indicador de error cuando ocurra un error, en lugar de lanzar una excepción cuando ocurra un error como connect. Si el método tiene éxito, el indicador de error es 0; de lo contrario, el indicador de error es el valor de la variable errno . Este método es útil para admitir, por ejemplo, conexiones asíncronas.
metodo publico
socket.recv(bufsize[, banderas]) Recibir datos, el valor devuelto es un objeto de byte, que representa los datos recibidos. bufsize especifica la cantidad máxima de datos que se pueden recibir a la vez.
socket.send(bytes[, banderas]) Para enviar datos, el Socket debe estar conectado a un Socket remoto. Este método devuelve el número de bytes enviados, que puede ser menor que el número de bytes en bytes .
socket.sendall(bytes[, banderas]) Para enviar datos, el Socket debe estar conectado a un Socket remoto y devolver Ninguno si se realiza correctamente. A diferencia del método de envío, este método seguirá enviando datos de bytes hasta que se hayan enviado todos los datos o se produzca un error.
socket.recvfrom(bufsize[, banderas]) Recibir datos, el valor devuelto es un par (bytes, dirección), donde bytes es un objeto de byte que representa los datos recibidos y dirección es la dirección del Socket que envió los datos.
socket.sendto(bytes, banderas, dirección) Enviar datos, el Socket no se puede conectar a un Socket remoto, porque la dirección especifica el Socket de destino. Este método devuelve el número de bytes enviados.
socket.cerrar() Cierra el enchufe.

4. Idea general de programación por Socket

4.1 La idea general de la programación de sockets basada en TCP

servidor [11] :

  • Crear servidor Socket: socket.socket(type=socket.SOCK_STREAM)
  • Vincule el socket del servidor creado a una ip y puerto: socket.bind()
  • Escuche la solicitud de conexión del cliente: socket.listen()
  • Acepte la solicitud de conexión del cliente: socket.accept()
  • Reciba datos del cliente o envíe datos al cliente: socket.recv() o socket.send()/socket.sendall()
  • Cierra la conexión: socket.close()

Cliente [11] :

  • Crear cliente Socket: socket.socket(type=socket.SOCK_STREAM)
  • Conecte el socket del cliente a la IP y el puerto del servidor: socket.connect(), socket.connect_ex()
  • Recibir datos del servidor o enviar datos al servidor: socket.recv(), o socket.send()/socket.sendall()
  • Cierra la conexión: socket.close()

El proceso anterior se puede resumir como se muestra en la Figura 4 a continuación:
inserte la descripción de la imagen aquí

Figura 4. Diagrama de flujo de la programación de Socket basada en TCP [11]
 

Tomemos como ejemplo las llamadas telefónicas diarias y primero entendamos la idea general de la programación Socket basada en TCP mencionada anteriormente de forma visual e intuitiva [6] . Si está interesado, puede obtener más información sobre el protocolo TCP.

Servidor - equivalente a la parte receptora :

  • Crear un socket de servidor: ¿Es equivalente a comprar un teléfono/teléfono móvil según el estándar de red, teléfono fijo, móvil 5G o teléfono satelital?
  • Vincular el Socket del servidor creado a una ip y puerto: es equivalente a solicitar un número de teléfono/móvil, a través del cual se puede contactar a la persona designada.
  • Escuchar la petición de conexión del cliente: equivale a conectar el teléfono/móvil a la red y esperar a que alguien llame.
  • Aceptar la solicitud de conexión del cliente: equivale a contestar el teléfono, para que se establezca una conexión de llamada.
  • Recibir datos del cliente, o enviar datos al cliente: es equivalente a hablar por teléfono y puede hablar en dos direcciones.
  • Cerrar Conexión: Equivalente a colgar el teléfono o apagar el teléfono/auricular.

Cliente - equivalente a la persona que llama :

  • Crear un socket de cliente: ¿es equivalente a comprar un teléfono/teléfono móvil según el estándar de red, teléfono fijo, teléfono móvil 5G o teléfono satelital?
  • Conectar el Socket del cliente a la ip y puerto del servidor: es equivalente a hacer una llamada, y hay que introducir el número de la otra parte.
  • Recibir datos del servidor, o enviar datos al servidor: es equivalente a hablar por teléfono, pudiendo hablar en dos direcciones.
  • Cerrar Conexión: Equivalente a colgar el teléfono o apagar el teléfono/auricular.

Al igual que nuestras llamadas diarias, ambas partes necesitan establecer una conexión antes de poder hablar. El servidor necesita usar los métodos socket.listen() y socket.accept(), y el cliente necesita usar socket.connect()/ método socket.connect_ex() primero Establezca una conexión entre sí antes de que pueda tener lugar la comunicación de red.


Notas :

  1. El host en la red se puede identificar de manera única por "dirección IP", y el programa de aplicación en el host se puede identificar de manera única por "protocolo + puerto" [12] . Vincule el Socket a una IP y un puerto, de modo que la aplicación correspondiente pueda comunicarse a través de la red a través del Socket.
  2. El parámetro backlog en el método socket.listen([backlog]) especifica el número máximo de conexiones que el sistema puede suspender antes de rechazar la conexión. Esto es similar a nuestras llamadas telefónicas diarias, si recibimos otras llamadas al mismo tiempo o durante la llamada, estas llamadas se pueden colgar y esperar hasta que sean contestadas.

A continuación, tomemos el siguiente código como ejemplo para comprender mejor la idea general de la programación Socket basada en TCP mencionada anteriormente.

#!/usr/bin/env python
# -*- coding:utf-8 -*-

""" 服务器 """

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建服务器Socket
s.bind(('127.0.0.1', 8888))  # 绑定创建的服务器Socket到一个ip和端口
s.listen(5)  # 监听客户端的连接请求
print("Waiting connection from client...")
conn, address = s.accept()  # 接受客户端的连接请求
print("Connected by {}".format(address))  # 打印客户端Socket的地址
receive_message = conn.recv(1024).decode()  # 接收客户端传来的数据并解码
print("Message received: {}".format(receive_message))  # 打印客户端传来的数据
send_message = receive_message.upper().encode()  # 将客户端传来的字符串转为大写之后,再编码发送回客户端
conn.send(send_message)  # 发送数据给客户端
conn.close()  # 关闭连接
s.close() 
#!/usr/bin/env python
# -*- coding:utf-8 -*-

""" 客户端 """

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)  # 创建客户端Socket
s.connect(('127.0.0.1', 8888))  # 连接客户端Socket到服务器ip和端口
print(s.getsockname())  # 打印客户端Socket的地址
send_message = 'Hello, world!'
s.send(send_message.encode())  # 发送数据给服务器
receive_message = s.recv(1024).decode()  # 接收服务器传来的数据并解码
print("Message received: {}".format(receive_message))  # 打印服务器传来的数据
s.close()  # 关闭连接

Ejecute primero el script del servidor y luego ejecute el script del cliente, los resultados son los siguientes:

""" 服务器 """

Waiting connection from client...
Connected by ('127.0.0.1', 52161)
Message received: Hello, world!
""" 客户端 """

('127.0.0.1', 52161)
Message received: HELLO, WORLD!

Los siguientes puntos deben tenerse en cuenta aquí:
1. Usamos el nuevo Socket (llamado Socket de servicio o Socket de conexión) devuelto por el método socket.accept() para comunicarnos con el cliente, no el Socket del servidor (llamado Socket de escucha) en sí. Para obtener más información sobre la supervisión del zócalo y el zócalo de servicio/el zócalo de conexión, consulte [13] y [14] .

2. Después de Python3, el socket transfiere datos de tipo bytes. La cadena debe convertirse primero, y string.encode() es suficiente; los datos de bytes recibidos por el otro extremo deben convertirse en una cadena, siempre que los bytes .decode() Solo hazlo [11] .


4.2 Idea general de la programación por Socket basada en UDP

En comparación con la programación de sockets basada en TCP, la programación de sockets basada en UDP es más simple. Dado que UDP no tiene el proceso de protocolo de enlace y activación de TCP, los métodos socket.listen(), socket.accept() y socket.connect()/socket.connect_ex() no son necesarios.

servidor :

  • Crear servidor Socket: socket.socket(type=socket.SOCK_DGRAM)
  • Vincule el socket del servidor creado a una ip y puerto: socket.bind()
  • Reciba datos del cliente o envíe datos al cliente: socket.recvfrom() o socket.sendto()
  • Cierra la conexión: socket.close()

cliente :

  • Crear cliente Socket: socket.socket(type=socket.SOCK_DGRAM)
  • Reciba datos del servidor o envíe datos al servidor: socket.recvfrom() o socket.sendto()
  • Cierra la conexión: socket.close()

El proceso anterior y la diferencia con la programación de Socket basada en TCP se pueden resumir como se muestra en la Figura 5 a continuación:
inserte la descripción de la imagen aquí

inserte la descripción de la imagen aquí

Figura 5. Comparación de la programación de sockets basada en TCP y la programación de sockets basada en UDP. La figura de arriba es el diagrama de flujo de la programación de Socket basada en TCP, y la figura de abajo es el diagrama de flujo de la programación de Socket basada en UDP. [15]
 

Tomemos como ejemplo los mensajes de texto diarios y primero entendamos la idea general de la programación de Socket basada en UDP de manera visual e intuitiva. Si está interesado, puede obtener más información sobre el protocolo UDP.

Servidor - equivalente a la parte receptora de SMS :

  • Crear un socket de servidor: ¿Es equivalente a comprar un teléfono móvil según el estándar de red, teléfono móvil 3G, teléfono móvil 4G o teléfono móvil 5G?
  • Vincular el servidor Socket creado a una ip y puerto: es equivalente a comprar una tarjeta telefónica, y puede contactar a la persona designada a través de este número.
  • Recibir datos del cliente, o enviar datos al cliente: equivalente a enviar y recibir mensajes de texto.
  • Cerrar conexión: Equivale a apagar el teléfono móvil.

Cliente - equivalente al lado emisor :

  • Crear un socket de cliente: ¿es equivalente a comprar un teléfono móvil según el estándar de red, teléfono móvil 3G, teléfono móvil 4G o teléfono móvil 5G?
  • Recibir datos del servidor, o enviar datos al servidor: equivalente a enviar y recibir mensajes de texto.
  • Cerrar conexión: Equivale a apagar el teléfono móvil.

A diferencia de hacer una llamada telefónica, enviamos y recibimos mensajes de texto todos los días. No es necesario que las dos partes establezcan una conexión primero. En cambio, una parte envía un mensaje de texto a la otra parte y la otra parte regresa después de recibir el mensaje. mensaje de texto. El cliente Socket envía el mensaje al servidor Socket con la dirección correspondiente especificando el parámetro de dirección a través del método socket.sendto(), que es equivalente a ingresar el número de teléfono móvil de la otra parte al enviar un mensaje de texto. Luego el servidor Socket recibe el mensaje a través del método socket.recvfrom() y devuelve la dirección de la otra parte, esto es equivalente a cuando recibimos un mensaje de texto de otra persona, el teléfono móvil no solo mostrará el contenido del texto mensaje enviado por la otra parte, pero también muestra el número de teléfono móvil de la otra parte. De esta forma, el servidor Socket puede enviar un mensaje al cliente especificando el parámetro de dirección a través del método socket.sendto(), lo que equivale a devolver un mensaje al número de teléfono móvil de la otra parte.

A continuación, tomemos el siguiente código como ejemplo para comprender mejor la idea general de la programación Socket basada en UDP mencionada anteriormente.

#!/usr/bin/env python
# -*- coding:utf-8 -*-

""" 服务器 """

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 创建服务器Socket
s.bind(('127.0.0.1', 8888))  # 绑定创建的服务器Socket到一个ip和端口
receive_message, address = s.recvfrom(1024)  # 接收客户端传来的数据
print("Receive message from {}".format(address))  # 打印客户端Socket的地址
receive_message = receive_message.decode()  # 解码客户端传来的数据
print("Message received: {}".format(receive_message))  # 打印客户端传来的数据
send_message = receive_message.upper().encode()  # 将客户端传来的字符串转为大写之后,再编码发送回客户端
s.sendto(send_message, address)  # 发送数据给客户端
s.close()  # 关闭连接
#!/usr/bin/env python
# -*- coding:utf-8 -*-

""" 客户端 """

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)  # 创建客户端Socket
send_message = 'Hello, world!'
s.sendto(send_message.encode(), ('127.0.0.1', 8888))  # 发送数据给服务器
print(s.getsockname())  # 打印客户端Socket的地址
receive_message, address = s.recvfrom(1024)  # 接收服务器传来的数据
print("Receive message from {}".format(address))  # 打印服务器Socket的地址
receive_message = receive_message.decode()  # 解码服务器传来的数据
print("Message received: {}".format(receive_message))  # 打印服务器传来的数据
s.close()  # 关闭连接

Ejecute primero el script del servidor y luego ejecute el script del cliente, los resultados son los siguientes:

""" 服务器 """

Receive message from ('127.0.0.1', 64410)
Message received: Hello, world!
""" 客户端 """

('0.0.0.0', 64410)
Receive message from ('127.0.0.1', 8888)
Message received: HELLO, WORLD!

Referencia

[1]: https://baike.baidu.com/item/%E5%A5%97%E6%8E%A5%E5%AD%97/9637606?fr=aladdin
[2]: https://baike.baidu.com/item/TCP/IP%E5%8D%8F%E8%AE%AE/212915
[3]: https://www.runoob.com/tcpip/tcpip-tutorial.html
[4]: https://www.cnblogs.com/jukaiit/p/6775404.html
[5]: https://www.jianshu.com/p/8c1f37361a89
[6]: https://zhuanlan.zhihu.com/p/137212690
[7]: https://www.runoob.com/python/python-socket.html
[8]: https://blog.51cto.com/xpleaf/1700032
[9]: https://researchlab.github.io/2018/09/20/socket-concept/
[10]: https://docs.python.org/3.10/library/socket.html#socket.socket
[11]: https://www.liujiangblog.com/course/python/76
[12]: https://blog.csdn.net/pashanhu6402/article/details/96428887
[13]: https://blog.csdn.net/phunxm/article/details/5085825
[14]: https://www.cnblogs.com/freebrid/p/4703096.html
[15]: https://zhuanlan.zhihu.com/p/73514975

Supongo que te gusta

Origin blog.csdn.net/Graduate2015/article/details/122209859
Recomendado
Clasificación