Comunicación Linux: solución de memoria compartida para crear comunicación de procesos IPC | Implementación de comunicación entre servidor y cliente mediante memoria compartida

La memoria compartida es la forma más rápida de IPC. Una vez que dicha memoria se asigna al espacio de direcciones del proceso que la comparte, estas transferencias de datos entre procesos ya no involucran al kernel, es decir, los procesos ya no se pasan los datos entre sí mediante la ejecución de llamadas al sistema en el kernel.

Tabla de contenido

1. El principio de la memoria compartida

2. Utilice la memoria compartida

3. Funciones de memoria compartida

1.shmget (usado para crear memoria compartida)

2.shmat (asociar memoria compartida con espacio de direcciones de proceso)

3.shmctl (usado para controlar la memoria compartida)

4.shmdt (separe el segmento de memoria compartida del proceso actual)

4. Prueba de comunicación entre servidor y cliente de memoria compartida

①Crear memoria compartida

 ②Asociar memoria y procesos compartidos

//2-3 Comunicar

③Cancelar la asociación entre el proceso y la memoria compartida.

④Cerrar memoria compartida


1. El principio de la memoria compartida

  • 1. Crea un espacio en la memoria física
  • 2. Deje que diferentes procesos asigne este espacio a su propio espacio de direcciones virtuales de proceso a través de la tabla de páginas.
  • 3. Diferentes procesos operan la memoria compartida operando direcciones virtuales en el espacio virtual de su propio proceso.

Los procesos A y B asignan sus direcciones virtuales a direcciones físicas a través de sus respectivas tablas de páginas. El proceso A opera la dirección virtual para escribir datos y los guarda en la memoria física, y el proceso B lee la memoria física.

2. Utilice la memoria compartida

La memoria compartida está en el espacio de direcciones físicas y en el área compartida.

  1. Crear memoria compartida
  2. Procesos asociados: establezca una relación de mapeo entre la dirección virtual del proceso y la dirección de la memoria compartida a través de la tabla de páginas.
  3. comunicación
  4. Desasociar el proceso: eliminando el valor-clave de la tabla de páginas en el proceso
  5. Liberación de memoria compartida

3. Funciones de memoria compartida

La figura anterior muestra que el proceso A y el proceso B pueden comunicarse a través de la memoria compartida y, de manera similar, C y D también pueden comunicarse a través de otra memoria compartida. Por lo tanto, en el sistema debe haber múltiples memorias compartidas al mismo tiempo, el sistema operativo necesita administrar estos bloques de memoria , por lo que se utiliza una estructura para almacenar los distintos atributos de la memoria compartida .

Entonces memoria compartida == estructura de datos del núcleo de memoria compartida + espacio físico abierto real

1.shmget (usado para crear memoria compartida)

Ejemplo: int shmget(key_t key,size_t size,int shmflg)

Parámetros: clave, el nombre de este segmento de memoria compartida, tamaño, el tamaño de la memoria compartida, shmflg, consta de nueve indicadores de permiso y el modo de uso es el mismo.

Valor de retorno: el éxito devuelve un número entero no negativo, que es el código de identificación del segmento de memoria compartida, el error devuelve -1

donde key_t key es un valor aleatorio generado por el algoritmo ftok y es único. La función ftok es la siguiente:

key_t ftok(const char * nombre de ruta,int proj_id)

Parámetro formal: nombre de ruta. Pase una dirección proj_id. Ingrese un número. Estos dos valores se pueden establecer arbitrariamente, pero deben ser los mismos en ambos lados de la comunicación. Específicamente, el proceso A llama a ftok para generar la clave. , coloca la clave en la estructura shm y B también la genera. Con la misma clave, B usa esta clave para hacer coincidir la estructura shm. Si la coincidencia es exitosa, se encuentra la memoria compartida.

macro shmflg significado
IPC_CREAT Cuando se usa solo, cree una memoria compartida. Si no existe, créela directamente. Si existe, obtenga la dirección inicial de la memoria compartida existente y devuélvala.
IPC_EXCL Debe confiar en IPC_CREAT para usarlo. Si no existe, cree la memoria compartida. Si existe, salga inmediatamente y devuelva un error.

2.shmat (asociar memoria compartida con espacio de direcciones de proceso)

Ejemplo: void * shmat(int shmid,const void * shmaddr,int shmflg);

Parámetros: shmid identificador de memoria compartida shmaddr especifica la dirección de la conexión shmflg sus dos valores posibles son SHM_RND y SHM_RDONLY

Valor de retorno: devuelve con éxito un puntero que apunta a la dirección inicial de la memoria compartida, si falla, devuelve -1 (similar a malloc)

Descripción: shmaddr es nulo, el sistema operativo selecciona automáticamente una dirección,

           shmaddr no es nulo y shmflg no tiene etiqueta SHM_RND, entonces shmaddr se usa como dirección de conexión.

         shmaddr no es nulo y shmflg establece el indicador SHM_RND, la dirección conectada se ajustará automáticamente hacia abajo en un múltiplo entero de shmlba.

            shmflg = SHM_RDONLY indica que la operación de conexión se utiliza para memoria compartida de solo lectura

3.shmctl (usado para controlar la memoria compartida)

Ejemplo: int shmctl(int shmid,int cmd,struct shmid_ds * buf);

Parámetros: código de identificación de memoria compartida de shmid devuelto por shmget

            cmd: La acción a realizar (hay tres valores posibles como se muestra en la siguiente tabla)

           buf: apunta a una estructura de datos que contiene el estado del modo y los permisos de acceso de la memoria compartida.

Valor de retorno: 0 en caso de éxito, -1 en caso de error

Orden ilustrar
IPC_STAT Establezca los datos en la estructura shmid_ds al valor asociado actual de la memoria compartida
IPC_SET Partiendo de la premisa de que el proceso tiene permisos suficientes, establezca el valor asociado actual de la memoria compartida en el valor proporcionado en la estructura de datos shmid_ds.
IPC_RMID Eliminar segmento de memoria compartida


4.shmdt (separe el segmento de memoria compartida del proceso actual)

Prototipo: int shmdt(const void * shmaddr);

Parámetros: shmaddr: puntero devuelto por shmat

Devuelve 0 en caso de éxito, -1 en caso de error

Nota: Desvincular la memoria compartida del proceso actual no significa eliminar el segmento de memoria compartida. 

4. Prueba de comunicación entre servidor y cliente de memoria compartida

Pasos para utilizar la comunicación de memoria compartida: crear memoria compartida, asociar proceso y memoria compartida, comunicar, cancelar asociación, eliminar memoria compartida

 Cree 4 archivos: server.cc, client.cc, common.hpp, makefile. El servidor implementa la escritura y el cliente implementa la lectura.

El archivo MAKE debe generar dos archivos de destino, servidor y cliente, y se puede escribir así:

.PHONY:all
all:server client
client:client.c comm.c
 gcc -o $@ $^
server:server.c comm.c
 gcc -o $@ $^
.PHONY:clean
clean:
 rm -f client server

Common.hpp declara y define algunas funciones comunes al cliente y al servidor, de la siguiente manera:

Este archivo implementa principalmente la creación de memoria compartida, asociación y cancelación de procesos y liberación de memoria compartida.

①Crear memoria compartida

  1. Primero, cree memoria compartida usando shmget
  2. Hay una clave, que se genera usando ftok y se puede llamar en ambos extremos\
  3. Al comunicarse, un proceso crea memoria compartida y otro proceso la adquiere.
  4.   Cuando se crea la memoria compartida, se mide en bytes.
//创建共享内存,要知道k和这个共享内存的大小
int createShm(key_t k, int size)
{
    //创建的时候,最好创建全新的
    int shmid = shmget(k,gsize,IPC_CREAT|IPC_EXCL);
    if(shmid == -1)
    {
       //创建失败
        exit(2);
    }
    
    return shmid;
}

//创建成功,一个进程获取
int getShm(key_t,int size)
{
    int shmid = shmget(k,gsize,IPC_CREAT);
    return shmid;
}

De las dos funciones anteriores, se crea una y se obtiene la otra, la única diferencia es shmflg, por lo que se puede encapsular en una función.

//static 只在本文件内有效
static int createShmHelper(int k, int size,int flag)
{
    int shmid = shmget(k,gsize,flag);
    if(shmid == -1)
    {
        exit(2);
    }

    return shmid;
}



int createShm(key_t k,int size)
{
      //创建的时候注意加权限
      umask(0);
      return createShmHelper(key,gsize,IPC_CREAT|IPC_EXCL|0666);
}

int getShm(key_t k,int size)
{
    return createShmHelper(key,gsize,IPC_CREAT);
}
    

 ②Asociar memoria y procesos compartidos

        Una vez creada la memoria compartida en la memoria física, la memoria compartida debe tener permisos cuando se crea para funcionar. Asocie la memoria compartida con el proceso. Coloque la dirección inicial de la memoria compartida en la PCB del proceso a través del mapeo de la tabla de páginas. Puede configurar usted mismo dónde conectarla a la PCB. Configúrelo en nulo para permitir que el sistema elija de forma independiente, eso es decir, la asociación se completa.

char * attachShm(int shmid)
{
    char * start = (char *)shmat(shmid,nullptr,0);
    return start;
}

//2-3 Comunicar

La comunicación específica puede ser configurada por usted mismo

③Cancelar la asociación entre el proceso y la memoria compartida.

detach(char * start)
{
    int n = shmdt(start);
    (void)n;
}

④Eliminar memoria compartida

Cuando se ejecuta en ambos extremos, se descubre que una vez que el proceso sale, la memoria compartida no se puede crear cuando se ejecuta nuevamente, lo que indica que la memoria compartida no se cierra directamente con el proceso.

Hay dos formas de desactivar la memoria compartida:

  1. comando ipcrm -m
  2. función shmctl
void delShm(int shmid)
{
   int n =  shmctl(shmid,IPC_RMID,nullptr);
   assert(n != -1);
   (void)n;
}

Server.cc implementa principalmente la creación de memoria compartida, la asociación de memoria compartida, la comunicación (lectura de datos de la memoria compartida), la cancelación de asociaciones y la eliminación de memoria compartida.

Client.cc implementa principalmente la obtención de memoria compartida, la asociación de memoria compartida, la comunicación (escribir datos en la memoria compartida) y la cancelación de asociaciones.

A continuación, modifique elegantemente el código anterior y encapsúlelo.

común.hpp:

//前面的方法不变


#define SERVER 1
#define CLIENT 0

class Init
{

public:
    //构造
    Init(int t):type(t)
    {
        key_t k = getKey();
        if(type == SERVER) 
            shmid = createShm(k, gsize);
        else
             shmid = getShm(k, gsize);

        start = attachShm(shmid);
    }

    char *getStart()
    {     
        return start;
    }

    //析构
    ~Init()
    {
        detachShm(start);
        if(type == SERVER) delShm(shmid);
    }
private:
    char *start;
    int type;     //server or client
    int shmid;
};


servidor.cc

int main()
{
    Init init(SERVER);
    char * start = init.getStart();
    //开始通信
    ....
    //读取
    int n = 0;
    while(n <= 26)
    {
        cout<<" "<<start<<endl;  //设置start里都是字符串
        sleep(1);
    }

    //因为init是一个临时对象,所以函数跑完会自动调用析构
    return 0;
}

cliente.cc

int main()
{
    Init init(CLIENT);
    char * start = init.getStart();
    
    //开始通信

    ...
    //往start里写
    char c = 'A';
    while(c <= 'Z')
    {
        start[c-'A'] = c;
        c++;
        start[c] = '\0';
        sleep(1);
    }

    return 0;
}

Supongo que te gusta

Origin blog.csdn.net/jolly0514/article/details/132562297
Recomendado
Clasificación