Una de las series de tecnología central para el desarrollo de aplicaciones distribuidas: diseño de mensajes originales basado en TCP/IP.

Este artículo es original y fue publicado por primera vez por el equipo técnico de Grape City. Indique la fuente de la reimpresión: Sitio web oficial de Grape City.Grape City proporciona a los desarrolladores herramientas, soluciones y servicios de desarrollo profesional para empoderar a los desarrolladores.

Prefacio

El contenido de este artículo se centra principalmente en las siguientes partes:

  1. Una breve introducción a TCP/IP.
  2. Introducción del mensaje.
  3. Formatos de transporte basados ​​en la clasificación de mensajes (tipo de flujo y tipo XML).
  4. La composición del sistema de mensajes.

Una breve introducción a TCP/IP

TCP/IP (Protocolo de control de transmisión/Protocolo de Internet) es el lenguaje o protocolo de comunicación básico en Internet. En realidad, es un programa de dos capas, dividido en alto y bajo nivel. El nivel superior es el Protocolo de control de transmisión, que se encarga de agregar información o dividir archivos en paquetes más pequeños. Estos paquetes se transmiten a través de la red a la capa TCP en el extremo receptor, y la capa TCP en el extremo receptor restaura los paquetes a los archivos originales. La capa inferior es el Protocolo de Internet, que maneja la parte de dirección de cada paquete para que llegue a su destino correctamente. Las computadoras de puerta de enlace en la red enrutan la información según su dirección. Incluso los subpaquetes del mismo archivo pueden enrutarse de manera diferente pero eventualmente convergen en el destino. TCP/IP utiliza un modelo cliente/servidor para la comunicación.

Desde el punto de vista arquitectónico, TCP/IP no se ajusta completamente al modelo de referencia de 7 capas de 0SI. El modelo de referencia de interconexión de sistema abierto tradicional es un modelo de referencia abstracto de 7 capas de un protocolo de comunicación, en el que cada capa realiza una tarea específica. El propósito de este modelo es permitir que varios hardware se comuniquen entre sí en el mismo nivel. Estas 7 capas son: capa física, capa de enlace de datos, capa de red, capa de transporte, capa de sesión, capa de presentación y capa de aplicación. El protocolo de comunicación TCP/IP adopta una estructura jerárquica de 4 capas, y cada capa llama a la red proporcionada por la siguiente capa para completar sus propias necesidades. Estas 4 capas son:

  • Capa de aplicación: la capa para la comunicación entre aplicaciones, como el Protocolo simple de transferencia de correo (SMTP), el Protocolo de transferencia de archivos (FTP), el Protocolo de acceso remoto a la red (Telnet), etc.
  • Capa de transporte: En esta capa proporciona transmisión de datos entre nodos y servicios de comunicación entre aplicaciones, sus funciones principales son formateo de datos, confirmación de datos y retransmisión de pérdidas, etc. Como el Protocolo de control de transmisión (TCP), el Protocolo de datagramas de usuario (UDP), etc. TCP y UDP agregan datos de transmisión al paquete de datos y los transmiten a la siguiente capa. Esta capa es responsable de transmitir los datos y determinar si los datos tienen sido entregado y recibir.
  • Capa de red de interconexión: Responsable de proporcionar funciones básicas de transmisión de paquetes de datos para que cada paquete de datos pueda llegar al host de destino (pero no verifica si se recibe correctamente), como el Protocolo de Internet (IP).
  • Capa de interfaz de red (capa de red host): recibe datagramas IP y los transmite, recibe tramas físicas de la red, extrae datagramas IP y los reenvía a la siguiente capa, administra los medios de red reales y define cómo usar la red real ( como Ethernet, línea serie, etc.) para transmitir datos.

Funciones comúnmente utilizadas en Tcp/IP

1.Función de enchufe

int socket(int domain,int type,int protocol),

dominio especifica el conjunto de protocolos utilizado, generalmente PF INET, que representa el conjunto de protocolos de Internet (conjunto de protocolos TCP/IP); el parámetro tipo especifica el tipo de socket; SOCK STREAM para TCP o SOCK DGRAM para UDP; al protocolo generalmente se le asigna un valor de [0]. La llamada a la función de socket devuelve un descriptor de socket entero, que se puede llamar más tarde.

2.función de enlace:

La función de vinculación asocia el socket con un puerto en la máquina local y luego escucha las solicitudes de servicio en ese puerto. El prototipo de la función de vinculación es:

int bind(int sockfd,struct sockaddr *my addr, int addrlen);

sockfd es el descriptor de socket devuelto al llamar a la función de socket; my addr es un puntero al tipo sockaddr que contiene información como la dirección IP local y el número de puerto: addrlen a menudo se establece en sizeof (struct sockaddr).

3.función de conexión de conexión:

El programa cliente orientado a la conexión utiliza la función de conexión para configurar el socket y establecer una conexión TCP con el servidor remoto. Su prototipo de función es:

int connect(int sockfd, struct sockaddr *serv addr,int addrlen);

sockfd es el descriptor de socket devuelto por la función de socket; serv addr es un puntero que contiene la dirección IP y el número de puerto del host remoto; addrlen es la longitud de la estructura de la dirección remota. La función de conexión devuelve -1 cuando ocurre un error y establece errno en el código de error correspondiente. No es necesario llamar a bind 0 al diseñar programas cliente, porque en este caso solo necesita conocer la dirección IP de la máquina de destino y el cliente no necesita preocuparse por qué puerto usa para establecer una conexión con el El programa ejecutor de socket selecciona automáticamente un puerto desocupado y notifica al programa cuando llegan datos al puerto.

4.escuchar función de escucha:

La función de escucha de red (escucha) pone el socket en modo de escucha pasiva y establece una cola de datos de entrada para el socket, guardando las solicitudes de servicio que llegan en esta cola hasta que el programa las procese.

int listen(int sockfd, int backlog);

sockfd es el descriptor de socket devuelto por la llamada al sistema Socket; backlog especifica el número máximo de solicitudes permitidas en la cola de solicitudes. Las solicitudes de conexión entrantes esperarán en la cola hasta que la función de recepción acepte 0) (ver más abajo). El trabajo pendiente limita el número de solicitudes en espera de servicio en la cola. Por lo general, el valor predeterminado del sistema es 20. Si llega una solicitud de servicio y la cola de entrada está llena, el socket rechazará la solicitud de conexión y el cliente recibirá un mensaje de error.

5.aceptar la función de recepción:

La función aceptar0 permite que el servidor acepte la solicitud de conexión del cliente. Después de establecer la cola de entrada, el servidor llama a la función de aceptación, luego duerme y espera la solicitud de conexión del cliente.

int accept(int sockfd, void *addr, int *addrlen);

sockfd es el descriptor del socket monitoreado, addr suele ser un puntero a la variable sockaddr_in, que se utiliza para almacenar información sobre el host que realiza el servicio de solicitud de conexión (un host envía la solicitud desde un determinado puerto); addrlen suele ser un puntero a Una variable de puntero entero cuyo valor es sizeof (struct sockaddr in). Cuando ocurre un error, la función de aceptación devuelve -1 y establece el código de error errno correspondiente.

6.función de envío y función de recepción:

int sendto(int sockfd, const void *msg,int len,unsigned int flags,const struct sockaddr *to, int tolen):

to representa la dirección IP y la información del número de puerto de la máquina de destino, y a tolen a menudo se le asigna el valor de sizeof (struct sockaddr). La función sendto devuelve la longitud real de los bytes de datos enviados o -1 en caso de un error de envío.

int recyfrom(int sockfd,void *buf,int len,unsigned int flags,structsockaddr *from,int *fromlen);

from es una variable de tipo struct sockaddr, que guarda la dirección IP y el número de puerto del host de origen. fromlen a menudo se establece en sizeof (struct sockaddr). Cuando recvfrom() regresa, fromlen contiene el número de bytes de datos realmente almacenados en from. La función recvfrom() devuelve el número de bytes recibidos o -1 cuando ocurre un error y establece el código de error errno correspondiente.

7.función de apagado

Función de apagado para cerrar el enchufe. Esta función le permite detener la transferencia de datos en una sola dirección mientras continúa la transferencia de datos en la otra dirección.

int shutdown(int sockfd,int how);

sockfd es el descriptor del socket que debe cerrarse. El parámetro how le permite elegir los siguientes métodos para la operación de apagado:

  • 0-1 No permitir seguir recibiendo datos
  • 1--No permitir seguir enviando datos
  • 2-No permitir más envío y recepción de datos

el apagado devuelve 0 cuando la operación es exitosa, devuelve -1 cuando ocurre un error y establece el código de error errno correspondiente.

8.función fcntl

La función fcntl puede cambiar las propiedades de un archivo abierto.

int fcntl (int fields, int cmd, .../* int arg */) ;

Nueve funciones getsockopt y setsockopt

Estas dos funciones pueden obtener o configurar opciones asociadas con un socket. Para manipular las opciones de la capa de socket, el valor de la capa debe especificarse como SOL SOCKET. Para operar las opciones de control de opciones de otras capas se debe proporcionar el número de protocolo apropiado. Por ejemplo, para indicar que TCP debe analizar una opción, la capa debe establecerse en el número de protocolo TCP.

int getsockopt(int sock, int level, int optname, void *optval, socklen_t *optlen);
int setsockopt(int sock, int level, int optname, const void *optval, socklen_t optlen);

10.seleccionar función

La función de selección es una llamada al sistema o una función utilizada para multiplexación. Generalmente se usa para manejar múltiples flujos de entrada y salida para implementar operaciones de E/S asincrónicas.

int select(int n, fd set * readfds, fd set * writefds, fd set * exceptfds,struct timeval * timeout);

El parámetro n representa el descriptor de archivo más grande más 1. Los parámetros readfds, writefds y exceptfds se denominan grupos de descriptores y se utilizan para devolver el estado de lectura, escritura o excepción del descriptor.

11.función de encuesta

int poll(struct pollfd fds[], nfds t nfds, int timeout);

Entre ellos, fds es una matriz del tipo de estructura struct pollfd, que se utiliza para almacenar el descriptor de socket cuyo estado debe detectarse. La definición de estructura pollfd es la siguiente:

struct pollfd {
        //descriptor to check
        int fd;
        //events of interest on fd
        short events;
        //events that occurred on fd
        short revents;
}

que es noticia

El mensaje es la unidad más pequeña a nivel de programación cuando se comunica entre dos entidades lógicas en la red en el desarrollo de aplicaciones distribuidas.

Aquí hay algunas explicaciones para la definición anterior:

(1) El concepto de mensaje existe en el trabajo de desarrollo y se ubica en el nivel de programación. Mientras el sistema está en ejecución, es transparente para los usuarios de la aplicación.

(2) Dos entidades lógicas en la red se refieren a dos programas que pueden ejecutarse de forma independiente, pueden implementarse en dos dispositivos físicos diferentes en la red o pueden implementarse en el mismo dispositivo físico, pero generalmente dos Un proceso independiente sin un relación padre-hijo (esto es diferente del concepto de mensaje más básico en la programación IPC).

(3) El mensaje es la unidad más pequeña a nivel de programación en la comunicación distribuida, es decir, no importa cuántos o pocos datos estén involucrados en la comunicación, el código del programa se implementa enviando y recibiendo uno o más mensajes.

(4) La comunicación entre dos aplicaciones en la red incluye dos tipos: transmisión de flujo de datos y llamada a procedimiento remoto (función).

(5) Los mensajes se pueden utilizar para lograr una comunicación de datos estructurada entre aplicaciones distribuidas. En otras palabras, lo que los programadores enfrentan a nivel de comunicación ya no es un flujo de bytes real, sino una unidad de datos estructurados que se puede combinar a partir de múltiples tipos de datos.

De hecho, esta unidad de datos estructurados en sí misma es un "mensaje" que puede representarse externamente como una estructura o clase. Por lo tanto, cuando se establece el mecanismo de mensaje basado en la definición anterior, los programadores solo necesitan generar el mensaje correspondiente cuando se necesita comunicación distribuida durante el proceso de codificación, y luego llamar a las interfaces de envío y recepción correspondientes para implementarlo convenientemente. Para comprender el conocimiento de TCP / IP, dominar las habilidades básicas de programación de sockets y no es necesario considerar otros problemas como demasiados mensajes en serie, demasiados mensajes concurrentes, control de flujo de red, etc., para que las aplicaciones distribuidas puedan realmente ser Los esfuerzos de desarrollo se concentran en la implementación comercial, lo que mejora en gran medida la eficiencia del desarrollo y la calidad de los sistemas distribuidos, especialmente los sistemas distribuidos a gran escala.

En cuanto a la forma de existencia del mensaje, en el lenguaje C tradicional, puede ser una estructura; en un lenguaje orientado a objetos (C++ o Java), puede ser una clase.

Formato de transmisión basado en la clasificación de mensajes.

Según los diferentes formatos de transmisión de mensajes, los mensajes se pueden dividir en mensajes de flujo y mensajes XML: los mensajes de flujo se transmiten en función del formato de transmisión de bytes binarios y los mensajes XML se transmiten en función de cadenas en formato XML.

mensajes en streaming

Los mensajes de flujo se refieren a mensajes que se transmiten y procesan en forma de flujo (flujo) en un sistema informático. Un mensaje de flujo consta de una serie de datos continuos, que se generan en el extremo emisor en un orden determinado y se transmiten al extremo receptor en forma de flujo. Durante el proceso de transmisión, el extremo receptor puede leer los datos del flujo uno por uno. Para los mensajes de flujo, no importa cómo el programador exprese el mensaje, el mensaje debe convertirse a un formato de flujo binario antes de enviarse realmente. Este proceso de conversión se llama Streamlización o Serilización.

mensaje XML

La mensajería XML se refiere a un método de transmisión de datos que utiliza el lenguaje de marcado extensible (XML) como formato de mensaje. XML es un lenguaje de marcado de texto que se utiliza para describir y almacenar datos. Utiliza etiquetas para definir la estructura y las propiedades de los datos. En el mecanismo de mensajes XML, después de que los programadores expresan el contenido del mensaje en formato XML, no necesitan realizar ningún trabajo de conversión de formato para enviar y transmitir (excluido el trabajo de cifrado para una transmisión segura) y pueden enviarlo directamente en formato de cadena XML. . Los mensajes XML también se utilizan ampliamente, por ejemplo, el protocolo SOAP en el servicio web está diseñado e implementado en base a mensajes XML.

Por ejemplo: método de diseño e implementación basado en mensajes en streaming.

El editor a continuación presentará brevemente cómo enviar y recibir información de una persona (incluida la altura, el nombre y la edad) en las dos aplicaciones.

(1) Defina una clase para almacenar la información de las personas:

struct Person {
        char name[20] ;
        float height;
        int age;
}
struct Person p;
strcpy(p.name ,"Michael Zhang");
height = 170.00;
age = 30;

(2) Estructurar la secuencia de información.

char sendStream[1024] = {0};
sprintf(sendStream,"|%s|%f"%d",p.name, p.height, p.age);

(3) El remitente envía un flujo de bytes:

/*注: 这里省略建立/管理/关闭 TCP 连接的代码*/
char datalen[4+1] = (0);
sprintf(datalen,"04d" , strlen (sendStream) );
if(SendBytes ( socket, datalen, 4) == -1) {
        return -l;
}
if(SendBytes(socket, sendStream, strlen(sendStream)) == -1) {
        return -1
}

Tenga en cuenta que la función SendBytes en el código anterior en realidad garantiza que todos los flujos de bytes de una determinada longitud se envíen correctamente antes de regresar, esto se debe principalmente a que llamar a la función de envío o escritura en el socket no puede garantizar que el flujo de bytes de una determinada longitud pueda enviarse. enviado completamente de una vez. . La idea básica de SendBytes es enviar en un bucle hasta que todos los bytes se envíen correctamente. El código de implementación es el siguiente:

int SendBytes (int sd, const void *buffer, unsigned len) {
        int rez = 0;
        int leftlen = len;
        int readlen = 0:
}
while(true) {
        rez = write (socket, (char *)buffer+readlen, len-readlen);
        if(rez < 0) {
                if (errno != EWOULDBLOCK && errno != EINTR) {
                        ErrorMsg("Error is serious );
                        DisConnect(socket);
        }
    return -l:
    }
    readlen += rez;
    leftlen -= rez;
    if(leftlen <= 0){
    break;
    }
   }
return len:
}

(4) El receptor recibe el flujo de bytes:

char datalen[4+1] = {0};
char receiveStream[1024] = {0};
sprintf(datalen,"%04d", strlen(sendStream)) ;
if(ReceiveBytes(socket, datalen, 4) == -1 {
        return -l;
}
int packet len = atoi(datalen) :
if(ReceiveBytes (socket, receiveStream, packet len) == -1) {
        return -l;
}

La función RecibirBytes puede referirse al tercer paso donde el remitente envía el flujo de bytes.

(5) Se deserializa el flujo de bytes para obtener la estructura:

struct Person p;
sscanf(receiveStream,"%[`|]|%f|%d", p.name, &p.height, &p.age) ;

Resumir

Este artículo presenta brevemente el protocolo TCP/IP y sus funciones de interfaz de uso común, luego presenta la clasificación y el formato de transmisión de mensajes en el protocolo TCP/IP y finalmente finaliza con un ejemplo simple de envío de mensajes. Si tiene algún comentario o sugerencia sobre el contenido, puede dejar mensajes y discutir en el área de comentarios.

Libro de referencia: "Diseño y desarrollo de mensajes: tecnología central del desarrollo de aplicaciones distribuidas" He Xiaochao

Enlace de extensión:

Desde el basado en formularios hasta el basado en modelos, interprete la tendencia de desarrollo de las plataformas de desarrollo de código bajo

¿Qué es una plataforma de desarrollo de código bajo?

La gestión de versiones basada en sucursales ayuda a que el código bajo pase de la entrega de proyectos al desarrollo de productos personalizados.

Lei Jun: La versión oficial del nuevo sistema operativo de Xiaomi, ThePaper OS, ha sido empaquetada. La ventana emergente en la página de lotería de la aplicación Gome insulta a su fundador. Ubuntu 23.10 se lanza oficialmente. ¡También podrías aprovechar el viernes para actualizar! Episodio de lanzamiento de Ubuntu 23.10: La imagen ISO fue "retirada" urgentemente debido a que contenía discurso de odio. Un estudiante de doctorado de 23 años solucionó el "error fantasma" de 22 años en Firefox. Se lanzó el escritorio remoto RustDesk 1.2.3. Wayland mejorado para soportar TiDB 7.4 Lanzamiento: Oficial Compatible con MySQL 8.0. Después de desconectar el receptor USB Logitech, el kernel de Linux falló. El maestro usó Scratch para frotar el simulador RISC-V y ejecutó con éxito el kernel de Linux. JetBrains lanzó Writerside, una herramienta para la creación de documentos técnicos.
{{o.nombre}}
{{m.nombre}}

Supongo que te gusta

Origin my.oschina.net/powertoolsteam/blog/10120032
Recomendado
Clasificación