Cómo construir un servidor de correo usando Python
Algunas personas dicen que es inútil simplemente aprender Python. Debes aprender un marco (como Django y web.py) para encontrar un trabajo.
De hecho, es útil dominar una herramienta avanzada similar a un framework, pero las cosas básicas pueden evitar que te eliminen y no dejes que las herramientas limiten tu desarrollo.
Hoy en día no utilizamos frameworks ni paquetes avanzados en la biblioteca estándar de Python. Solo utilizamos la interfaz de socket en la biblioteca estándar para escribir un servidor Python.
Marco y capa inferior
En la era actual de los marcos de servidor Python (marcos como Django, Twisted, web.py, etc.), parece que escribir un servidor desde el socket inferior ser una manera ingrata y estúpida.
La importancia del marco es ocultar los detalles subyacentes, proporcionar un conjunto de API que sean más amigables para los desarrolladores y manejar problemas de diseño como MVC.
El marco nos permite construir rápidamente un servidor Python maduro y maduro. Sin embargo, el marco en sí también depende de la capa subyacente (como el socket). Comprender el socket subyacente no solo nos ayuda a utilizar mejor el marco, sino que también nos permite comprender cómo está diseñado.
Además, si tiene buenos conocimientos de programación de sockets subyacentes y otros conocimientos de programación de sistemas, puede diseñar y desarrollar su propio marco.
Si puede comenzar desde el socket subyacente, implementar un servidor Python completo, admitir protocolos a nivel de usuario y manejar problemas como MVC (Model-View-Control) y subprocesos múltiples (threading), y Al clasificar un conjunto claro de funciones o clases y presentarlas a los usuarios como una interfaz (API), equivale a diseñar un marco.
La interfaz de socket es en realidad una llamada al sistema proporcionada por el sistema operativo.
El uso de sockets no se limita al lenguaje Python. Puedes escribir el mismo servidor de sockets en C o Java, y todos los lenguajes usan sockets de manera similar (Apache es un servidor implementado en C). ).
Pero no puedes usar frameworks en todos los idiomas.
La ventaja del marco es que le ayuda a manejar algunos detalles para lograr un desarrollo rápido, pero también está limitado por el rendimiento del propio Python.
Hemos visto que muchos sitios web exitosos se desarrollan rápidamente utilizando lenguajes dinámicos (como Python, Ruby o PHP, como Twitter y Facebook). Una vez que el sitio web tiene éxito, el código se convierte. en lenguajes como C y JAVA. Estos lenguajes relativamente eficientes permiten que el servidor enfrente de manera más eficiente cientos de millones de solicitudes todos los días.
En este caso, la importancia de la capa inferior supera con creces la de la estructura.
Introducción a TCP/IP y sockets
Volvemos a nuestra tarea.
Necesitamos tener una cierta comprensión de la transmisión de red, especialmente del protocolo TCP/IP y los sockets.
Socket es un método de comunicación entre procesos. Es una interfaz de capa superior basada en el protocolo de transmisión de red.
Existen muchos tipos de sockets, como los basados en el protocolo TCP o el protocolo UDP (dos protocolos de transmisión de red), entre los cuales el socket TCP es el más utilizado.
El socket TCP es algo similar a una tubería bidireccional (PIPE dúplex). Un proceso escribe o lee un flujo de texto en un extremo del socket, mientras que otro proceso puede leer o escribir desde el otro extremo del socket. Comparar En particular, los dos procesos que establecen la comunicación por socket pueden pertenecer a dos computadoras diferentes.
El protocolo TCP estipula algunas reglas de comunicación para que el proceso de comunicación entre procesos mencionado anteriormente se pueda realizar de manera efectiva en un entorno de red.
Una tubería bidireccional (PIPE dúplex) sobrevive en la misma computadora, por lo que no es necesario distinguir las direcciones de las computadoras donde se encuentran los dos procesos, y el socket debe contener información de dirección para lograr comunicación en red.
Un socket contiene cuatro informaciones de dirección: las direcciones IP de dos ordenadores y los puertos utilizados por los dos procesos. La dirección IP se usa para ubicar la computadora y el puerto se usa para ubicar el proceso (puede haber múltiples procesos en una computadora usando diferentes puertos).
Socket TCP
En Internet, deje que un ordenador actúe como servidor.
El servidor abre su propio puerto y espera pasivamente a que se conecten otros ordenadores.
Cuando otras computadoras actúan como clientes y utilizan activamente sockets para conectarse al servidor, el servidor comienza a brindar servicios a los clientes.
En Python, utilizamos el paquete de sockets en la biblioteca estándar para realizar programación de sockets de bajo nivel.
Primero está el lado del servidor. Usamos el método bind() para darle al socket una dirección y un puerto fijos, y usamos el método listening() para escuchar pasivamente el puerto.
Cuando un cliente intenta conectarse usando el método connect(), el servidor usa aceptar() para aceptar la conexión y establecer un socket conectado:
socket.socket() crea un objeto socket y explica que el socket utiliza IPv4 (AF_INET, IP versión 4) y el protocolo TCP (SOCK_STREAM).
Luego, usando otra computadora como cliente, usamos activamente el método connect() para buscar la dirección IP del lado del servidor (en Linux, puedes usar $ifconfig para consultar tu propia dirección IP) y el puerto. , para que el cliente pueda encontrar el servidor y establecer una conexión:
En el ejemplo anterior, podemos llamar al método recv() para recibir información y al método sendall() para enviar información en ambos extremos de el enchufe.
De esta forma podremos comunicarnos entre dos procesos ubicados en dos ordenadores.
Cuando finaliza la comunicación, utilizamos el método close() para cerrar la conexión del socket.
(Si no tiene dos computadoras para realizar experimentos, también puede cambiar la IP del cliente al que desea conectarse a "127.0.0.1". Esta es una dirección IP especial que se utiliza para conectarse al local host.)
Servidor HTTP basado en socket TCP
En el ejemplo anterior, ya podemos usar socket TCP para establecer una conexión entre dos computadoras remotas.
Sin embargo, la libertad de transmisión del socket es demasiado alta, lo que trae muchos problemas de seguridad y compatibilidad.
A menudo utilizamos algunos protocolos de capa de aplicación (como el protocolo HTTP) para estipular las reglas de uso del socket y el formato de la información transmitida.
El protocolo HTTP utiliza el método solicitud-respuesta (solicitud-respuesta) para utilizar el socket TCP.
El cliente envía un fragmento de texto al servidor como solicitud. Después de recibir la solicitud, el servidor envía un fragmento de texto al cliente como respuesta.
Después de completar dicha transacción de solicitud-respuesta, el socket TCP se descarta.
La siguiente solicitud creará un nuevo socket.
La solicitud y la respuesta son esencialmente dos textos, pero el protocolo HTTP tiene ciertos requisitos de formato para ambos textos.
Solicitud lt;——gt; Respuesta
Ahora, escribimos un servidor HTTP:
Explicación del programa del servidor HTTP
Como Como vimos arriba, el servidor utilizará una de las dos piezas de información text_content y pic_content transmitidas al cliente en función de la solicitud como texto de respuesta.
Toda la respuesta se divide en tres partes: línea de salida, cabeza y cuerpo. La línea de inicio es la primera línea:
En realidad, está dividida en tres fragmentos por espacios. HTTP/1.x representa la versión HTTP utilizada, 200 representa el estado (código de estado) y 200 es HTTP As. Lo estipulado en el protocolo significa que el servidor recibe y procesa la solicitud normalmente. OK es un código de estado para que lo lean los humanos.
La información del encabezado sigue a la línea de inicio, con una línea en blanco entre esta y el cuerpo.
Aquí text_content o pic_content solo tiene una línea de información de encabezado. El tipo de text_content utilizado para representar la información principal es texto html:
Y la información de encabezado de pic_content (Contenido-). Tipo: imagen/jpg) indica que el tipo de sujeto es imagen jpg (imagen/jpg).
La información principal es el contenido del archivo html o jpg.
(Tenga en cuenta que para los archivos jpg, utilizamos el modo "rb" para abrirlos por compatibilidad con Windows. Porque en Windows, jpg se considera un archivo binario, pero en sistemas UNIX, no es necesario distinguirlo. entre archivos de texto y archivos binarios)
No hemos escrito un programa cliente, usaremos el navegador como cliente más adelante.
La solicitud es enviada al servidor por el programa cliente.
Aunque la solicitud se puede dividir en tres partes como la respuesta, el formato de la solicitud no es el mismo que el formato de la respuesta.
La solicitud es enviada al servidor por el cliente. Por ejemplo, la siguiente es una solicitud:
La línea de inicio se puede dividir en tres partes. La primera parte es la solicitud. método (método de solicitud), la segunda parte es la URL y la tercera parte es la versión HTTP.
El método de solicitud puede incluir GET, PUT, POST, DELETE y HEAD. Los más utilizados son GET y POST.
GET solicita al servidor que envíe recursos al cliente y POST solicita al servidor que reciba los datos enviados por el cliente.
Cuando abrimos una página web, normalmente utilizamos el método GET; cuando rellenamos un formulario y lo enviamos, normalmente utilizamos el método POST.
La segunda parte es la URL, que normalmente apunta a un recurso (un recurso en el servidor o en otro lugar). Como ahora, test.jpg apunta al directorio actual del servidor actual.
Según lo dispuesto en el protocolo HTTP, el servidor necesita realizar determinadas operaciones según la solicitud.
Como podemos ver en el programa del servidor, nuestro programa Python primero verifica el método de solicitud y luego genera diferentes respuestas (text_content o pic_content) según diferentes URL.
Posteriormente, la respuesta se envía de vuelta al cliente.
Uso de experimentos con el navegador
Para cooperar con el programa de servidor anterior, guardé un archivo de imagen test.jpg en la carpeta donde se encuentra el programa Python.
Ejecutamos el programa Python anterior en la terminal como servidor y luego abrimos un navegador como cliente.
(Si tiene tiempo, también puede escribir un cliente en Python. El principio es similar al programa cliente de socket TCP anterior).
En la barra de direcciones del navegador, ingrese :
(Por supuesto, también puedes usar una computadora e ingresar la dirección IP del servidor)
OK, ya tengo uno implementado en Python, y desde el socket escribí el servidor.
Desde el terminal podemos ver que el navegador realmente realizó dos solicitudes.
La primera solicitud es (la información clave está en la línea inicial, el cuerpo de esta solicitud está vacío):
Nuestro programa Python envía el contenido de text_content al servidor según esta petición.
Después de que el navegador recibió text_content, descubrió que había lt;IMG src="text.jpg" /gt; en el texto html del texto principal. Sabía que necesitaba obtener el texto. jpg para complementarlo como imagen y lo enviamos inmediatamente. Segunda solicitud:
Después de que nuestro programa Python analizó la línea de inicio, descubrió que /test.jpg cumplía la condición if, por lo que pic_content se envió al cliente.
Finalmente, el navegador muestra el texto HTML y las imágenes de forma adecuada según la sintaxis del lenguaje HTML.
Direcciones de exploración
1) En nuestro programa de servidor anterior, utilizamos un bucle while para mantener el servidor funcionando.
De hecho, también podemos cambiar el contenido del bucle while a trabajo multiproceso o multiproceso según el conocimiento de multiproceso.
2) Nuestro programa de servidor aún no es perfecto. También podemos dejar que nuestro programa Python llame a otras funciones de Python para lograr funciones más complejas. Por ejemplo, cree un servidor de hora y deje que el servidor devuelva la fecha y la hora al cliente. También puede utilizar la propia base de datos de Python para implementar un servidor LAMP completo.
3) El paquete socket es un paquete de nivel relativamente bajo. También hay paquetes de alto nivel en la biblioteca estándar de Python, como SocketServer, SimpleHTTPServer, CGIHTTPServer y cgi. Todos estos están incluidos para ayudarnos a utilizar los enchufes más fácilmente. Si ya conoce los sockets, estos paquetes son fáciles de entender. Con estos paquetes de alto nivel, puede escribir un servidor bastante maduro.
4) Después de pasar por todo el arduo trabajo y los problemas, es posible que descubra que el marco es muy conveniente, por lo que decide utilizarlo. O bien, ya le apasiona participar en el desarrollo del marco.