分布式Server:Server

源程序:【免费】分布式Server:Server资源-CSDN文库

#include <stdio.h>
#include <stdlib.h>
#include <cstring>
/* IDL_TypeSupport.h中包含所有依赖的头文件 */
#include "IDL_TypeSupport.h"

int flag = 0;
float avg[3], avs;
char ID[3][100];
bool zcy = false;
/* UserDataTypeListener继承于DataReaderListener,
 需要重写其继承过来的方法on_data_available(),在其中进行数据监听读取操作 */
class UserDataTypeListener : public DataReaderListener {
public:
    virtual void on_data_available(DataReader* reader);
};
/* 重写继承过来的方法on_data_available(),在其中进行数据监听读取操作 */
void UserDataTypeListener::on_data_available(DataReader* reader)
{
    GradeDataReader* Grade_reader = NULL;
    GradeSeq data_seq;
    SampleInfoSeq info_seq;
    ReturnCode_t retcode;
    int i;
    /* 利用reader,创建一个读取UserDataType类型的UserDataType_reader*/
    Grade_reader = GradeDataReader::narrow(reader);
    if (Grade_reader == NULL) {
        fprintf(stderr, "DataReader narrow error\n");
        return;
    }

    /* 获取数据,存放至data_seq,data_seq是一个队列 */
    retcode = Grade_reader->read(
        data_seq, info_seq, 10, 0, 0, 0);
    if (retcode == RETCODE_NO_DATA) {
        return;
    }
    else if (retcode != RETCODE_OK) {
        fprintf(stderr, "take error %d\n", retcode);
        return;
    }
    avg[flag] = data_seq[0].score;
    strcpy_s(ID[flag], 100, data_seq[0].ID);
    flag++;
    if (flag == 3)
    {
        avs = (avg[0] + avg[1] + avg[2]) / 3;
        flag = 0;
        zcy = true;
    }
    /* 打印数据 */
    /* 建议1:避免在此进行复杂数据处理 */
    /* 建议2:将数据传送到其他数据处理线程中进行处理 *
    /* 建议3:假如数据结构中有string类型,用完后需手动释放 */

    for (i = 0; i < data_seq.length(); ++i)
    {
        printf("receive: name=%s,ID=%s,score=%f\n",
            data_seq[i].name, data_seq[i].ID, data_seq[i].score);
        delete data_seq[i].name;
        data_seq[i].name = NULL;
        delete data_seq[i].ID;
        data_seq[i].ID = NULL;
    }
}
/* 删除所有实体 */
static int subscriber_shutdown(
    DomainParticipant* participant)
{
    ReturnCode_t retcode;
    int status = 0;
    if (participant != NULL) {
        retcode = participant->delete_contained_entities();
        if (retcode != RETCODE_OK) {
            fprintf(stderr, "delete_contained_entities error %d\n", retcode);
            status = -1;
        }
        retcode = DomainParticipantFactory::get_instance()->delete_participant(participant);
        if (retcode != RETCODE_OK) {
            fprintf(stderr, "delete_participant error %d\n", retcode);
            status = -1;
        }
    }
    return status;
}
/* 订阅者函数 */
extern "C" int subscriber_main(int domainId, int sample_count)
{
    DomainParticipant* participant = NULL;
    Subscriber* subscriber = NULL;
    Publisher* publisher = NULL;
    Topic* topic1 = NULL;
    Topic* topic2 = NULL;
    UserDataTypeListener* reader_listener = NULL;
    DataReader* reader = NULL;
    DataWriter* writer = NULL;
    ReturnCode_t retcode1,retcode2;
    AverageGradeDataWriter* AverageGrade_writer = NULL;
    AverageGrade* tpc_avggrade = NULL;
    const char* type_name1 = NULL;
    const char* type_name2 = NULL;
    int count = 0;
    int status = 0;
    InstanceHandle_t instance_handle = HANDLE_NIL;
    /* 1. 创建一个participant,可以在此处定制participant的QoS */
    /* 建议1:在程序启动后优先创建participant,进行资源初始化*/
    /* 建议2:相同的domainId只创建一次participant,重复创建会占用大量资源 */
    participant = DomainParticipantFactory::get_instance()->create_participant(
        domainId, PARTICIPANT_QOS_DEFAULT/* participant默认QoS */,
        NULL /* listener */, STATUS_MASK_NONE);
    if (participant == NULL) {
        fprintf(stderr, "create_participant error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    /* 2. 创建一个subscriber,可以在创建subscriber的同时定制其QoS */
    /* 建议1:在程序启动后优先创建subscriber*/
    /* 建议2:一个participant下创建一个subscriber即可,无需重复创建 */
    subscriber = participant->create_subscriber(
        SUBSCRIBER_QOS_DEFAULT/* 默认QoS */,
        NULL /* listener */, STATUS_MASK_NONE);
    if (subscriber == NULL) {
        fprintf(stderr, "create_subscriber error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    publisher = participant->create_publisher(
        PUBLISHER_QOS_DEFAULT /* 默认QoS */,
        NULL /* listener */, STATUS_MASK_NONE);
    if (publisher == NULL) {
        fprintf(stderr, "create_publisher error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    /* 3. 在创建主题之前注册数据类型 */
    /* 建议1:在程序启动后优先进行注册 */
    /* 建议2:一个数据类型注册一次即可 */
    type_name1 = GradeTypeSupport::get_type_name();
    type_name2 = AverageGradeTypeSupport::get_type_name();
    retcode1 = GradeTypeSupport::register_type(
        participant, type_name1);
    retcode2 = AverageGradeTypeSupport::register_type(
        participant, type_name2);
    if (retcode1 != RETCODE_OK) {
        fprintf(stderr, "register_type error %d\n", retcode1);
        subscriber_shutdown(participant);
        return -1;
    }
    if (retcode2 != RETCODE_OK) {
        fprintf(stderr, "register_type error %d\n", retcode2);
        subscriber_shutdown(participant);
        return -1;
    }
    /* 4. 创建主题,并定制主题的QoS */
    /* 建议1:在程序启动后优先创建Topic */
    /* 建议2:一种主题名创建一次即可,无需重复创建 */
    topic1 = participant->create_topic(
        "tpc_Grade"/* 主题名,应与发布者主题名一致 */,
        type_name1, TOPIC_QOS_DEFAULT/* 默认QoS */,
        NULL /* listener */, STATUS_MASK_NONE);
    if (topic1 == NULL) {
        fprintf(stderr, "create_topic error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    topic2 = participant->create_topic(
        "tpc_AvgGrade"/* 主题名,应与发布者主题名一致 */,
        type_name2, TOPIC_QOS_DEFAULT/* 默认QoS */,
        NULL /* listener */, STATUS_MASK_NONE);
    if (topic2 == NULL) {
        fprintf(stderr, "create_topic error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    /* 5. 创建一个监听器 */
    reader_listener = new UserDataTypeListener();

    /*6.1创建datawriter*/
    writer = publisher->create_datawriter(
        topic2, DATAWRITER_QOS_DEFAULT/* 默认QoS */,
        NULL /* listener */, STATUS_MASK_NONE);
    if (writer == NULL) {
        fprintf(stderr, "create_datawriter error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    AverageGrade_writer = AverageGradeDataWriter::narrow(writer);
    if (AverageGrade_writer == NULL) {
        fprintf(stderr, "DataWriter narrow error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    tpc_avggrade = AverageGradeTypeSupport::create_data();
    if (tpc_avggrade == NULL) {
        fprintf(stderr, "AverageGradeTypeSupport::create_data error\n");
        subscriber_shutdown(participant);
        return -1;
    }
    /* 6. 创建datareader,并定制datareader的QoS */
    /* 建议1:在程序启动后优先创建datareader*/
    /* 建议2:创建一次即可,无需重复创建 */
    /* 建议3:在程序退出时再进行释放 */
    /* 建议4:避免打算接收数据时创建datareader,接收数据后删除,该做法消耗资源,影响性能 */
    reader = subscriber->create_datareader(
        topic1, DATAREADER_QOS_DEFAULT/* 默认QoS */,
        reader_listener/* listener */, STATUS_MASK_ALL);
    if (reader == NULL) {
        fprintf(stderr, "create_datareader error\n");
        subscriber_shutdown(participant);
        delete reader_listener;
        return -1;
    }
    /* 7. 主循环 ,监听器会默认调用on_data_available()监听数据 */
    for (count = 0; (sample_count == 0) || (count < sample_count); ++count) {
        //保持进程一直运行
        /*while (zcy == false)
        {
            reader_listener->on_data_available(reader);
        }*/
        if (zcy == true)
        {
            tpc_avggrade->ID1 = new char[100];
            tpc_avggrade->ID2 = new char[100];
            tpc_avggrade->ID3 = new char[100];
            tpc_avggrade->avgScore = avs;
            strcpy_s(tpc_avggrade->ID1, 100, ID[0]);
            strcpy_s(tpc_avggrade->ID2, 100, ID[1]);
            strcpy_s(tpc_avggrade->ID3, 100, ID[2]);
            retcode2 = AverageGrade_writer->write(*tpc_avggrade, instance_handle);
            if (retcode2 != RETCODE_OK)
            {
                fprintf(stderr, "write error %d\n", retcode2);
            }
            else
                fprintf(stderr, "%d : write successfully . . \n", count);
            zcy = false;
        }
    }
    retcode2 = AverageGradeTypeSupport::delete_data(tpc_avggrade);
    if (retcode2 != RETCODE_OK) {
        fprintf(stderr, "AverageGradeTypeSupport::delete_data error %d\n", retcode2);
    }
    printf("%s\n", "到最后一步了");
    /* 8. 删除所有实体和监听器 */
    status = subscriber_shutdown(participant);
    delete reader_listener;
    return status;
}
int main(int argc, char* argv[])
{
    int domain_id = 0;
    int sample_count = 0; /* 无限循环 */
    if (argc >= 2) {
        domain_id = atoi(argv[1]); //发送至域domain_id 
    }
    if (argc >= 3) {
        sample_count = atoi(argv[2]);// 发送sample_count次 
    }
    return subscriber_main(domain_id, sample_count);
}

这段代码是一个使用DDS(Data Distribution Service,数据分发服务)API的订阅者应用示例。DDS是一种中间件协议,用于在分布式系统中发布和订阅数据。该代码示例展示了如何创建一个订阅者,接收Grade类型的数据,计算三个成绩的平均值,并将结果以AverageGrade类型的数据发布出去。

主要部分解析

  1. 创建参与者(Participant)
    使用DomainParticipantFactory创建一个参与者,该参与者在指定的域ID中运行。

  2. 创建订阅者(Subscriber)和发布者(Publisher)
    在参与者下分别创建订阅者和发布者。

  3. 注册数据类型
    注册GradeAverageGrade数据类型,这是DDS通信的基础。

  4. 创建主题(Topic)
    GradeAverageGrade数据类型分别创建主题。

  5. 创建数据读取器(DataReader)和数据写入器(DataWriter)
    在订阅者下创建Grade数据读取器,在发布者下创建AverageGrade数据写入器。

  6. 数据接收与处理
    UserDataTypeListeneron_data_available方法中接收Grade数据,计算平均值,并在满足条件时通过AverageGrade_writer发布结果。

  7. 资源清理
    在程序结束时,删除所有实体并释放资源。

潜在问题指出

  1. 内存管理
    • UserDataTypeListener::on_data_available方法中,对data_seq中的nameID字段进行了手动内存释放。这种做法的前提是DDS实现确实为这些字符串分配了需要手动释放的内存。然而,这通常不是DDS API的标准行为,因为DDS通常负责其内部数据结构的内存管理。这里的内存释放可能会导致未定义行为,除非这些字符串确实是由DDS API动态分配的。
    • subscriber_main函数中,为tpc_avggradeID1ID2ID3字段分配了内存,但在程序结束时没有释放这些内存,导致内存泄漏。
  2. 错误处理
    • 代码中的错误处理主要是通过打印错误信息并返回错误状态。在实际应用中,可能需要更复杂的错误处理逻辑,比如重试机制或向用户报告错误。
  3. 代码风格与可读性
    • 代码中存在一些硬编码的值(如字符串长度100),这些值最好定义为常量以提高代码的可读性和可维护性。
    • 变量命名(如IDL_sIDL_strtpc_avggrade等)可能不够直观,使用更具描述性的命名可以提高代码的可读性。
  4. 逻辑问题
    • UserDataTypeListener::on_data_available方法中,avgID数组以及flagzcy变量是在类外部定义的,这在多线程环境中可能导致数据竞争。这些变量应该是线程安全的,或者on_data_available方法应该是线程隔离的。
    • zcy变量用于控制何时发布平均成绩。然而,如果on_data_available方法在没有接收到足够数据的情况下被多次调用(例如,由于网络延迟或数据发布者的速率限制),则可能永远不会发布平均成绩。考虑实现一个更健壮的机制来触发平均成绩的计算和发布。
  5. 未使用的代码
    • writerAverageGrade_writer在创建后被用于发布平均成绩,但publisher变量在创建后未被使用。虽然这不会影响程序的正确性,但最好是清理未使用的变量以提高代码的可读性和可维护性。同样地,topic2也未被实际使用(除了创建writer时),也应该被清理。

建议

  • 重新审视内存管理策略,确保内存的正确分配和释放。
  • 增强错误处理逻辑,以提供更健壮的错误报告和恢复机制。
  • 改善代码风格和变量命名以提高可读性。
  • 确保所有共享数据在多线程环境中都是线程安全的。
  • 清理未使用的变量和代码以提高可维护性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值