proceso de recepción de mensajes fdbus

Cómo enviar mensajes en fdbus. Algunos artículos anteriores han entrado en gran detalle, pero menos sobre cómo recibir mensajes. Este artículo se centra en cómo fdbus recibe mensajes y el proceso de entrega de mensajes y el método de entrega (¿copia cero?).

Hablemos de ello a través del código fuente. Es más simple. La recepción de mensajes debe realizarse a través de sockets, pero no encontré un lugar para leer los sockets en un bucle. Solo puedo hablar de las funciones en la parte media. pero esta parte ya se puede hacer, el procesamiento de la recepción de mensajes se explica claramente. No hay mucho que decir, aquí está el código:

void CFdbSession::onInput()
{
    if (fatalError())
    {
        goto _quit;
    }
    uint8_t prefix_buffer[CFdbMessage::mPrefixSize];
    if (receiveData(prefix_buffer, sizeof(prefix_buffer)))
    {
        parsePrefix(prefix_buffer);
    }
    if (fatalError())
    {
        goto _quit;
    }
    if (receiveData(mPayloadBuffer + CFdbMessage::mPrefixSize,
                     mMsgPrefix.mTotalLength - CFdbMessage::mPrefixSize))
    {
        processPayload();
    }

_quit:
    if (mPayloadBuffer)
    {
        delete[] mPayloadBuffer;
        mPayloadBuffer = 0;
    }
}

En el código anterior, puede ver que el prefijo en la estructura del mensaje se obtiene llamando al método recibirData, y luego la parte del prefijo del mensaje se analiza llamando a parsePrefix. Luego llame a ReceiverData para obtener el contenido del mensaje en la estructura del mensaje y finalmente llame a ProcessPayload para procesar el mensaje. El código fuente del método ProcessPayload es el siguiente:

void CBaseSession::processPayload()
{
    const uint8_t *data = mPayloadBuffer + CFdbMessage::mPrefixSize;
    int32_t size = mMsgPrefix.mTotalLength - CFdbMessage::mPrefixSize;
    if (size < 0)
    {
        fatalError(true);
        return;
    }

    CFdbMessageHeader head;
    CFdbParcelableParser parser(head);
    if (!parser.parse(data, mMsgPrefix.mHeadLength))
    {
        LOG_E("CBaseSession: Session %d: Unable to deserialize message head!\n", sid());
        fatalError(true);
        return;
    }

    auto type = head.type();
    switch (type)
    {
        case FDB_MT_REQUEST:
        case FDB_MT_SIDEBAND_REQUEST:
        case FDB_MT_GET_EVENT:
        case FDB_MT_PUBLISH:
        case FDB_MT_SET_EVENT:
            doStatistics(type, head.flag(), mStatistics.mRx);
            doRequest(head);
            break;
        case FDB_MT_RETURN_EVENT:
        case FDB_MT_REPLY:
        case FDB_MT_SIDEBAND_REPLY:
        case FDB_MT_STATUS:
            doResponse(head);
            break;
        case FDB_MT_BROADCAST:
            doStatistics(type, head.flag(), mStatistics.mRx);
            doBroadcast(head);
            break;
        case FDB_MT_SUBSCRIBE_REQ:
            if (head.code() == FDB_CODE_SUBSCRIBE)
            {
                doSubscribeReq(head, true);
            }
            else if (head.code() == FDB_CODE_UNSUBSCRIBE)
            {
                doSubscribeReq(head, false);
            }
            break;
        default:
            LOG_E("CBaseSession: Message %d: Unknown type!\n", (int32_t)head.serial_number());
            fatalError(true);
            break;
    }
}

Primero, obtenga el contenido del mensaje (comenzando desde el encabezado del mensaje), los primeros datos de la dirección y la longitud del contenido del mensaje, y llame a la clase CFdbParcelableParser para analizar el contenido del encabezado del mensaje. Después de obtener el encabezado del mensaje, la información básica del mensaje se obtiene, incluido el tipo de mensaje mType. Se ingresan diferentes ramas para el procesamiento dependiendo del tipo de mensaje. Aquí nos centramos en el tipo FDB_MT_REPLY, porque este es el tipo de respuesta del mensaje e implicará el método mencionado anteriormente de reemplazar el contenido del mensaje de respuesta recibido con los parámetros de entrada y salida del función en el hilo de llamada. Consulte lo siguiente para una implementación detallada:

void CBaseSession::doResponse(CFdbMessageHeader &head)
{
    bool found;
    PendingMsgTable_t::EntryContainer_t::iterator it;
    CBaseJob::Ptr &msg_ref = mPendingMsgTable.retrieveEntry(head.serial_number(), it, found);
    if (found)
    {
        auto msg = castToMessage<CFdbMessage *>(msg_ref);
        auto object_id = head.object_id();
        if (msg->objectId() != object_id)
        {
            LOG_E("CFdbSession: object id of response %d does not match that in request: %d\n",
                    object_id, msg->objectId());
            terminateMessage(msg_ref, FDB_ST_OBJECT_NOT_FOUND, "Object ID does not match.");
            mPendingMsgTable.deleteEntry(it);
            delete[] mPayloadBuffer;
            mPayloadBuffer = 0;
            return;
        }

        auto object = mContainer->owner()->getObject(msg, false);
        if (object)
        {
            msg->update(head, mMsgPrefix);
            msg->decodeDebugInfo(head);
            msg->replaceBuffer(mPayloadBuffer, head.payload_size(), mMsgPrefix.mHeadLength);
            mPayloadBuffer = 0;
            auto type = msg->type();
            doStatistics(type, head.flag(), mStatistics.mRx);
            if (!msg->sync())
            {
                switch (type)
                {
                    case FDB_MT_REQUEST:
                        object->doReply(msg_ref);
                    break;
                    case FDB_MT_SIDEBAND_REQUEST:
                        object->onSidebandReply(msg_ref);
                    break;
                    case FDB_MT_GET_EVENT:
                        object->doReturnEvent(msg_ref);
                    break;
                    case FDB_MT_SET_EVENT:
                    default:
                        if (head.type() == FDB_MT_STATUS)
                        {
                            object->doStatus(msg_ref);
                        }
                        else
                        {
                            LOG_E("CFdbSession: request type %d doesn't match response type %d!\n",
                                  type, head.type());
                        }
                    break;
                }
            }
        }

        msg_ref->terminate(msg_ref);
        mPendingMsgTable.deleteEntry(it);
    }
}

Como puede ver en el código anterior, primero se obtiene el número de secuencia mSn en el encabezado del mensaje. El número de secuencia en cada mensaje enviado es único. Al responder después de que se completa el procesamiento del punto final de la red, el número de secuencia del mensaje también debe ser devuelto para que el original El remitente del mensaje de solicitud determina si envía un mensaje que coincida con él en función del número de secuencia.

código anterior

CBaseJob::Ptr &msg_ref = mPendingMsgTable.retrieveEntry(head.serial_number(), it, encontrado);

Simplemente completa la lógica. Si se encuentra un mensaje coincidente, se procesa y el puntero del objeto de mensaje del solicitante del mensaje original se encuentra a través del número de secuencia. Aquí viene la parte más crítica. Cada objeto de sesión contiene un puntero mPayloadBuffer que apunta al mensaje recibido y el memoria a la que apunta este puntero Cada vez que se recibe un mensaje, se volverá a aplicar y luego se pasará la siguiente declaración

msg->replaceBuffer(mPayloadBuffer, head.payload_size(), mMsgPrefix.mHeadLength);

Complete la sustitución del contenido del cuerpo del mensaje.

Finalmente, al llamar a la siguiente declaración, si hay una llamada sincrónica, active el hilo de llamada activando la variable de condición y desbloquee el hilo de llamada. Al mismo tiempo, también completó el reemplazo del contenido del mensaje de respuesta al mBuffer y otros miembros señalados por el puntero del objeto de mensaje original. Para ser más sencillo, al recibir un mensaje, el objeto de sesión primero solicita una memoria. , Y luego el mensaje recibido se lee en la memoria. Luego analiza el encabezado del mensaje. Después de analizar el encabezado del mensaje, obtiene el número de secuencia del mensaje y luego encuentra el objeto del mensaje enviado localmente a través del número de secuencia. El objeto del mensaje contiene miembros como mBuffer mPayloadSize mHeadSize mOffset. Después de encontrar el objeto, primero libere la memoria apuntada por mBuffer. y luego asigne la memoria solicitada por el objeto de sesión a mBuffer, completando así el proceso de entrega del mensaje. De esta manera, cuando la llamada sincrónica Cuando se realiza, el objeto señalado por el parámetro CBaseJob::Ptr &msg_ref completa el cambio del mensaje de solicitud original al mensaje de respuesta. El usuario puede obtener el mensaje de respuesta completo de este parámetro.

msg_ref->terminar(msg_ref);

De esta forma todos entenderán el proceso completo de un mensaje. Siento que está bastante claro.

Supongo que te gusta

Origin blog.csdn.net/iqanchao/article/details/133377545
Recomendado
Clasificación