¿De qué habla exactamente la skynet de Yunfeng?

Skynet de Yunfeng se define como un marco de servidor de juegos, implementado con c + lua basado en el modelo Actor. El código está extremadamente simplificado, con solo unas 3000 líneas de código en la parte c.
El problema central que debe resolver todo el marco de skynet es enviar un mensaje (paquete de datos) de un servicio (Actor) a otro servicio (Actor) y recibir su devolución. Es decir, un servicio en el mismo proceso (el autor también enfatiza que no se limita al mismo proceso, porque puede haber comunicación entre clústeres) un servicio que llama a otro servicio en el mismo proceso a través de un rpc similar y recibe el procesamiento. resultado. Skynet se ocupa de las reglas y la corrección del envío de paquetes de datos entre estos servicios.
La capa central de skynet es realizada por c.
Cuando el sistema se inicia, obtendrá una identificación de nodo preasignada, que llamamos la identificación del puerto. Esta identificación es utilizada por el clúster. Muchos nodos de skynet se pueden iniciar en un clúster, y a cada nodo se le asignará una identificación única.
Hay muchos servicios en un nodo (es decir, un proceso), y los servicios pueden entenderse temporalmente como módulos funcionales en un sentido estricto.
Cuando se inicializa un servicio, se genera un skynet_context como una instancia del servicio; un identificador de servicio único (incluso en un clúster), es decir, la identificación única del servicio, se usa para identificar el servicio; una cola de mensajes message_queue; También registre una devolución de llamada con el marco, y cuando el servicio recibe un mensaje enviado, se pasa a través de este método.
El código para inicializar un servicio es el siguiente:

struct skynet_context *
skynet_context_new(const char * name, const char *param) {
    
    
     // 装载模块
     struct skynet_module * mod = skynet_module_query(name);

     if (mod == NULL)
          return NULL;

     void *inst = skynet_module_instance_create(mod);
     if (inst == NULL)
          return NULL;
     // 初始化skynet_context实例
     struct skynet_context * ctx = skynet_malloc(sizeof(*ctx));
     CHECKCALLING_INIT(ctx)

     ctx->mod = mod;
     ctx->instance = inst;
     ctx->ref = 2;
     ctx->cb = NULL;
     ctx->cb_ud = NULL;
     ctx->session_id = 0;
     ctx->logfile = NULL;

     ctx->init = false;
     ctx->endless = false;
     // 初始化服务handle
     // Should set to 0 first to avoid skynet_handle_retireall get an uninitialized handle
     ctx->handle = 0;    
     ctx->handle = skynet_handle_register(ctx);
     // 初始化消息队列
     struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
     // init function maybe use ctx->handle, so it must init at last
     context_inc();

     CHECKCALLING_BEGIN(ctx)
     int r = skynet_module_instance_init(mod, inst, ctx, param);
     CHECKCALLING_END(ctx)
     if (r == 0) {
    
    
          struct skynet_context * ret = skynet_context_release(ctx);
          if (ret) {
    
    
               ctx->init = true;
          }
          skynet_globalmq_push(queue);
          if (ret) {
    
    
               skynet_error(ret, "LAUNCH %s %s", name, param ? param : "");
          }
          return ret;
     } else {
    
    
          skynet_error(ctx, "FAILED launch %s", name);
          uint32_t handle = ctx->handle;
          skynet_context_release(ctx);
          skynet_handle_retire(handle);
          struct drop_t d = {
    
     handle };
          skynet_mq_release(queue, drop_message, &d);
          return NULL;
     }
}
 在skynet_handle_register方法中生成一个服务handle,handle是一个32位的整数,在生成handle的时候,是把该节点的harbor id写到了handle的高8位里面,所以一个服务的handle,就可以知道这个服务是哪个节点的。
   s->handle_index = handle + 1;
      rwlock_wunlock(&s->lock);
      handle |= s->harbor;
      return handle;   

Por lo tanto, la identificación de puerto más alta es solo 256, lo que significa que el clúster de skynet solo puede tener 256 nodos como máximo, y un nodo solo puede tener 24 servicios como máximo, es decir, 1.6M. Debido a que un identificador es un número entero de 32 bits, los 8 bits superiores se utilizan para almacenar la identificación del puerto y solo los 24 bits inferiores se utilizan para asignar el identificador del nodo.
La cola de mensajes message_queue se utiliza para almacenar mensajes enviados al servicio. Todos los mensajes enviados al servicio primero deben presionarse en la cola de mensajes del servicio.

 服务启动起来了,来看看数据包是如何从一个服务发送给另一个服务的。
 来看看 skynet_send 和 callback 函数的定义:
int skynet_send(
  struct skynet_context * context,
  uint32_t source,
  uint32_t destination,
  int type,
  int session,
  void * msg,
  size_t sz
);

typedef int (*skynet_cb)(
  struct skynet_context * context,
  void *ud,
  int type,
  int session,
  uint32_t source ,
  const void * msg,
  size_t sz
);

El origen y el destino son los identificadores del remitente y del receptor, respectivamente.
El tipo es la
sesión de protocolo utilizada por el remitente y el receptor para procesar paquetes de datos para identificar la contraseña de esta llamada. Después de que el remitente envía un mensaje, retiene la sesión para que cuando se reciba el paquete de respuesta, pueda identificar cuál es la llamada. es.
msg / sz es el contenido y la longitud del paquete de datos, usado en pares

Envío de mensajes de Skynet

Skynet mantiene una cola de mensajes de dos niveles.

Cada entidad de servicio tiene una cola de mensajes privada, en la que los mensajes se le envían uno por uno. El mensaje consta de cuatro partes:

struct skynet_message {
    
    
    uint32_t source;
    int session;
    void * data;
    size_t sz;
};

Enviar un mensaje a un servicio es presionar el cuerpo del mensaje en la cola de mensajes privados del servicio. El valor de esta estructura se copia en la cola de mensajes, pero el contenido del mensaje en sí no se copia.

Skynet mantiene una cola de mensajes global, que contiene colas de mensajes secundarios no vacías.

Cuando se inicia Skynet, se establecen varios subprocesos de trabajo (el número es configurable) y continuamente sacan una cola de mensajes secundaria de la cola de mensajes principal, luego toman un mensaje de la cola secundaria y llaman a la función de devolución de llamada del servicio correspondiente Hazlo. Para llamar a la justicia, solo procese un mensaje a la vez, en lugar de consumir todos los mensajes (aunque esa parte es más eficiente porque reduce la cantidad de entidades de servicio de consulta y la cantidad de veces que la cola de mensajes principal entra y sale), por lo que que ningún servicio pasará hambre.

De esta forma, skynet se da cuenta de que se envía un mensaje (paquete de datos) de un servicio a otro.

Recomendar a todos un campo de entrenamiento sobre el combate real del proyecto skynet. La inscripción ahora es equivalente a gratuita. El contenido principal:


Cola de mensajes de programación simultánea de varios núcleos .
Programación de mensajes del actor del grupo de subprocesos
Implementación del módulo de red Implementación del
temporizador de rueda de tiempo
Programación de interfaz lua / c / Programación de
conceptos básicos de programación Skynet
demuestra el pensamiento de programación del actor

Dirección: Haga clic para ver el video
Más información sobre skynet más grupo: 832218493 ¡Consígalo gratis!
Inserte la descripción de la imagen aquí

Supongo que te gusta

Origin blog.csdn.net/lingshengxueyuan/article/details/112273489
Recomendado
Clasificación