Programación del sistema Linux C (15) Programación avanzada de red

1 programación de zócalos en profundidad    

Existen muchas técnicas avanzadas en la programación de sockets. El uso de estas técnicas puede operar mejor el socket y completar la tarea de comunicación de red; dominar estas habilidades puede desarrollar mejor las aplicaciones de red de alta calidad.

1.1 El papel importante de la función de enlace

La característica más destacada del programa del lado del servidor y del programa del lado del cliente es que el cliente no necesita una función de supervisión de enlace. La función de vinculación vincula el zócalo a una dirección IP y un número de puerto; si la función de vinculación no se utiliza para vincular la dirección y el puerto, el núcleo vinculará automáticamente el zócalo al llamar a las funciones de escuchar y conectar. La función de vinculación se puede omitir; pero la forma de vinculación de escuchar y conectar es realmente diferente, como se muestra a continuación:

  1. enlace de escucha: no hay ningún parámetro de estructura de dirección en la función de escucha, por lo que el sistema solo puede establecer la dirección IP y el número de puerto.
  2. Enlace de conexión: utilice una estructura establecida (sockaddr_in) como parámetro, la estructura especifica el servidor que se va a vincular.

El programa del lado del servidor no se preocupa por la dirección IP del cliente, el núcleo lo vinculará a cualquier valor (INADDR_ANY), y el núcleo también asignará un puerto disponible al puerto. (Debido a que es una asignación temporal, hará que se usen diferentes puertos cada vez que se ejecute el programa del servidor, lo que requiere que el programa cliente cambie el número de puerto cada vez, lo que no es realista).
A partir de esto, la función de vinculación es Las palabras son importantes    

1.2 Servidores concurrentes

La desventaja del servidor orientado a la conexión en el frente es que solo puede manejar una solicitud de cliente a la vez, pero si un programa de cliente ocupa el servidor, los otros clientes estarán "hambrientos" para trabajar; por lo tanto, en En realidad, un servidor orientado a la conexión no utiliza un marco de bucle, sino que utiliza un proceso para procesar múltiples solicitudes, es decir, un servidor concurrente. El proceso de ejecución del servidor concurrente (pseudocódigo) es el siguiente:

//地址结构初始化;
fd=socket();
bind(fd,...);
listen(fd,...);
while(1){
     accept_fd=accept(fd,...);
     if(fork(...)==0){
          //与客户端交互,处理来自客户端的请求;
          close(accept_fd);
     }
     close(accept_fd);
}
close(fd);
close函数失败的处理。

El servidor concurrente resuelve la situación en la que el cliente del servidor de bucle monopoliza el servidor, pero también deben tenerse en cuenta dos problemas nuevos:

  1. La creación de procesos secundarios requiere muchos recursos y debe usar algoritmos excelentes para mejorar la eficiencia.
  2. Una vez que finaliza el proceso secundario, preste atención a la recuperación de recursos, que es un problema potencial que puede bloquear el sistema.    

1.3 Aplicación de función de conexión de protocolo UDP

La función de conexión también se puede usar para conexiones UDP. Aunque UDP pertenece al protocolo de comunicación sin conexión, si la dirección de destino del datagrama siempre se fija durante la comunicación, esta operación es innecesaria cada vez. En este momento, use connect to love you En cambio, una conexión hace que la comunicación sea más eficiente. En este momento, el flujo de ejecución del cliente es consistente con el cliente orientado a la conexión; la diferencia es que uno está orientado a la conexión y el otro no está orientado a la conexión. El proceso (pseudocódigo) es el siguiente:

//地址结构初始化;
fd=socket(“UDP”);
connect(fd,...);
//与服务器交互,向服务器发出具体消息/接受来自服务器的消息;
close(fd);

Cuando el volumen de comunicación de datos es grande, la eficiencia de este método será mayor que el método tradicional de comunicación sin conexión.


2 E / S multiplexadas

La E / S multicanal es otro método de procesamiento de E / S, que es más eficiente que la E / S tradicional. Es típico de aprovechar al máximo el tiempo y se usa comúnmente en aplicaciones de red.

2.1 El concepto de E / S multiplexada

La E / S multiplexada es principalmente para evitar el bloqueo de E / S y evitar que el proceso caiga en un estado muerto. La idea de este método es construir una tabla de dispositivos (generalmente una descripción de archivo) que necesita leer datos, llamar a una función para sondear los dispositivos en esta tabla y saber que hay un dispositivo que puede leer y escribir, la función regresa. El modelo de E / S multicanal se muestra en la figura:
 

La E / S del sistema múltiple requiere dos llamadas al sistema:

  1. Responsable de verificar y devolver los descriptores de archivos de los dispositivos disponibles.
  2. Responsable de leer y escribir el descriptor de archivo.

2.2 Realizar E / S de selección multicanal

En Linux, la función de selección se usa para implementar la E / S seleccionada. El prototipo de la función es el siguiente:

#include <sys/select.h>     /* According to earlier standards */
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
//fd_set这种数据类型本质上是一个位向量,即一个无符号整数;每一位代表一个状态,为1表示被设置,为0表示没有被设置,

//linux环境下提供专门对这种向量进行操作的函数,如下所示:
void FD_CLR(int fd, fd_set *set);          //清除向量指定的位。
int  FD_ISSET(int fd, fd_set *set);     //测试向量指定的位是否被设置,fd表示需要测试的位。
void FD_SET(int fd, fd_set *set);          //设置向量指定的位。
void FD_ZERO(fd_set *set);               //清空位向量所有的位。
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
部分参数说明:
参数timeout如果为NULL则表示一直等待设备就绪,是一种死等设备的方法。
如果readfds、writefds、exceptfds都被置为NULL,即表示对三种状态都不关心,则此时select函数成为一个精度为微秒的定时器;select函数将一直查询各个设备,直到时间耗尽为止。  
函数返回值:正常返回准备好的设备数;如果为0,表示没有设备准备好;为-1表示出错。

Consulte el manual de referencia de la función de Linux para más detalles . Nota: Por defecto, un proceso tiene hasta 1024 descriptores de archivo.    

2.3 E / S de selección múltiple de señal blindada

La diferencia entre la función pselect y la función select:

  1. El último parámetro de pselect es una opción de protección de señal, es decir, tiene la función de protección de señal; las señales que no se pueden proteger incluyen SIGKILL y SIGSTOP. (Evite que programas maliciosos ataquen la computadora)
  2. La estructura utilizada para el parámetro de tiempo en pselect es timepec. La precisión mínima que la estructura de timepec puede representar es nanosegundos; si se usa como temporizador, será el temporizador más preciso en Linux.

En Linux, la función pselect se utiliza para lograr una selección múltiple de señales blindadas. El prototipo de la función es el siguiente:

int pselect(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, const struct timespec *timeout,const sigset_t *sigmask);

Consulte el manual de referencia de la función de Linux para más detalles .

2.4 Proceso del lado del servidor de E / S multiplexadas

//地址结构初始化;
fd=socket();
bind(fd,...);
listen(fd,...);
//FD系列函数的操作,初始化
     FD_ZERO();
     FD_SET();
     FD_ISET();
     FD_CLR();
while(1){
     numner_fd=select();
     accept_fd=accept(fd,...);
     与客户端交互,处理来自客户端的请求;
     close(fd);
     if(--number_fd<=0)
          break;
}
close(fd);
close函数失败的处理。

2.5 E / S de sondeo

La función select no admite STREAMS en uso, por lo que el sistema agrega la función de sondeo en función de select. La función de sondeo admite varios tipos de descriptores de archivos para la multiplexación de E / S; pero a diferencia de select, la función de sondeo Establezca un pollfd de estructura de operación para cada descriptor de archivo que se supervisará de forma independiente. La estructura describe el comportamiento de supervisión y los eventos que ocurren en el descriptor de archivo de destino. La estructura se define de la siguiente manera:

# include < sys/ poll. h>
struct pollfd {
     int fd;         /* 文件描述符 */
     short events;         /* 等待的事件;用户所关心的操作 */
     short revents;       /* 实际发生了的事件;文件描述符上已经发生的事件 */
} ;

Los miembros de eventos y respiraderos establecen una o más de las siguientes combinaciones de logotipos, como se muestra en la tabla:

Nota: Los eventos de miembros no se pueden establecer como marcas de excepción; los miembros evitan que los datos se devuelvan cuando se llama a la función de sondeo, por lo que no es necesario configurarlos antes de la llamada. El prototipo de la función de encuesta en Linux es el siguiente:    

#include <poll.h>
int poll(struct pollfd *fds, nfds_t nfds, int timeout);

Consulte el manual de referencia de la función de Linux para más detalles .


3 Toma de comunicación sin red

El socket de comunicación que no es de red se utiliza principalmente para la comunicación de procesos en la máquina; dado que las direcciones IP de los procesos en la máquina son las mismas, solo se necesita el número de proceso para determinar a ambas partes en la comunicación.

3.1 Socket de dominio UNIX sin nombre

Linux utiliza la función socketpair para crear un par de sockets de dominio UNIX interconectados sin nombre. El prototipo de la función es el siguiente:

#include <sys/types.h>         
#include <sys/socket.h>
int socketpair(int domain, int type, int protocol, int sv[2]);

Consulte el manual de referencia de la función de Linux para más detalles . La función socketpair crea un par de sockets de dominio UNIX sin nombre. Dado que no hay nombre, otros procesos no pueden usar el socket para comunicarse. Es decir, solo se guardan los descriptores de archivo de sockets de dominio UNIX sin nombre. Los procesos pueden usarlo. Esto es algo similar a una tubería. El proceso padre crea un proceso hijo, los cuales guardan los descriptores de archivo en ambos extremos de la tubería, y luego cierran el final de la tubería para iniciar la comunicación.

3.2 Nombrar sockets de dominio UNIX

Los sockets de dominio UNIX sin nombre limitan el alcance de la comunicación y no son flexibles; los sockets con nombre pueden resolver este problema. Al igual que los sockets de comunicación de red, los sockets de dominio UNIX también necesitan vincular direcciones, pero debido a que los dominios utilizados por los dos son diferentes, sus familias de direcciones también son diferentes. En el sistema Linux, el socket de dominio UNIX usa la estructura sockaddr_un para almacenar la dirección, y su prototipo de estructura es el siguiente:

#include <sys/un.h>
struct sockaddr_un{
    sa_family_t sun_family;          //表示地址使用的族,即AF_UNIX
    char sun_path[108];              //套接字文件的路径名
};

Cuando la dirección está vinculada a un socket de dominio UNIX, el sistema crea un archivo cuyo nombre de ruta es el nombre de ruta indicado en sun_path y el tipo es S_IFSOCK. Este archivo no se puede abrir y todos los procesos que necesitan comunicarse están vinculados a este archivo, que funciona como una estación de retransmisión de información. Al llamar a la función de enlace para el enlace de dirección, debe pasar el tamaño de la matriz de caracteres sun_path como parámetro al núcleo. La forma habitual de escritura es:

int sfd;
struct sockaddr_un un;
bind(sfd, (struct sockaddr *)*un,  sizeof(struct scokaddr_un) - sizeof(sa_family_t));

Consulte el manual de referencia de la función de Linux para más detalles . Entre ellos, el tamaño de sun_path es sizeof (struct scokaddr_un) -sizeof (sa_family_t), esto es para mejorar la portabilidad del código. Nota:

  1. Cuando el cliente crea un socket local, es necesario llamar a bind para que se una a la ruta correspondiente. Este es un paso necesario. A diferencia de los sockets de red, de hecho, la programación de sockets de red también requiere la vinculación, pero el kernel se ejecuta automáticamente de forma implícita. Vinculante
  2. Antes de crear un enlace de zócalo, debe desvincular el archivo de zócalo de la ruta previamente enlazada, de lo contrario, el enlace producirá un error;
  3. Después de vincular el socket a la ruta correspondiente, si ya no necesita conectarse a otros sockets a través de la ruta con nombre, puede desvincular la ruta con nombre.

Se puede ver que el proceso utiliza el archivo de disco del archivo socket para la comunicación, pero no quiere que la entrada del directorio del archivo exista cada vez que se realiza el enlace de dirección. Por lo general, el archivo de disco de socket de proceso del servidor existirá durante mucho tiempo y sus entradas de directorio se eliminarán y crearán continuamente. Cada conexión de cliente se creará cuando la dirección del servidor esté vinculada, y luego se eliminará el archivo. La siguiente conexión de cliente no podrá vincular la dirección del servidor. El archivo de socket del proceso del cliente se elimina después de que se completa la comunicación, y cada proceso de cliente debe tener un archivo de socket; para garantizar la unicidad del archivo en el sistema, la práctica habitual es utilizar la ID del proceso como archivo Nombre, para que pueda asegurarse de que el nombre del archivo no entre en conflicto.

3.3 Procesos y precauciones del lado del servidor y del lado del cliente de los sockets de dominio UNIX

Los sockets de dominio UNIX se usan de la misma manera que los sockets de comunicación de red, y también se dividen en procesos de servidor y procesos de cliente. El flujo de ejecución del servidor y el flujo de ejecución del cliente son consistentes con el flujo de ejecución del socket de comunicación de red.

Publicado 289 artículos originales · elogiados 47 · 30,000+ vistas

Supongo que te gusta

Origin blog.csdn.net/vviccc/article/details/105175132
Recomendado
Clasificación