当前位置:首页 > C > 正文

C语言发布订阅模式(手把手教你用C实现事件驱动的消息通信机制)

在软件开发中,发布订阅模式(Publish-Subscribe Pattern)是一种非常重要的事件驱动编程设计思想。它允许组件之间松耦合地通信:发布者(Publisher)发送消息,而无需知道谁会接收;订阅者(Subscriber)监听感兴趣的消息,而无需知道谁发布了它。这种模式在 GUI 编程、消息中间件、嵌入式系统等领域广泛应用。

虽然 C 语言不像 Java 或 Python 那样内置面向对象特性,但我们依然可以用结构体和函数指针来优雅地实现 C语言发布订阅模式。本文将从零开始,带你一步步构建一个简易但完整的发布订阅系统,适合编程小白理解。

C语言发布订阅模式(手把手教你用C实现事件驱动的消息通信机制) C语言发布订阅模式 事件驱动编程C语言 观察者模式C实现 消息传递机制C语言 第1张

一、核心概念解析

  • 主题(Topic):消息的分类标识,比如 "temperature_update"。
  • 发布者(Publisher):向某个主题发送消息的组件。
  • 订阅者(Subscriber):注册到某个主题,并在消息发布时被通知的回调函数。
  • 事件总线(Event Bus):管理所有主题与订阅者映射关系的中枢。

二、数据结构设计

我们首先定义几个关键结构:

#include <stdio.h>#include <stdlib.h>#include <string.h>// 订阅者回调函数类型typedef void (*subscriber_callback_t)(const char* topic, const void* data);// 单个订阅者节点typedef struct SubscriberNode {    subscriber_callback_t callback;    struct SubscriberNode* next;} SubscriberNode;// 主题条目(哈希表中的一个桶)typedef struct TopicEntry {    char* topic_name;    SubscriberNode* subscribers;    struct TopicEntry* next; // 用于处理哈希冲突} TopicEntry;// 事件总线typedef struct EventBus {    TopicEntry** buckets;  // 哈希表数组    int bucket_count;} EventBus;

三、核心函数实现

接下来我们实现初始化、订阅、发布等关键功能。

1. 初始化事件总线

#define DEFAULT_BUCKET_COUNT 16unsigned int hash(const char* str) {    unsigned int hash = 5381;    int c;    while ((c = *str++))        hash = ((hash << 5) + hash) + c; // djb2 算法    return hash;}EventBus* event_bus_create() {    EventBus* bus = (EventBus*)malloc(sizeof(EventBus));    bus->bucket_count = DEFAULT_BUCKET_COUNT;    bus->buckets = (TopicEntry**)calloc(DEFAULT_BUCKET_COUNT, sizeof(TopicEntry*));    return bus;}

2. 订阅主题

void event_bus_subscribe(EventBus* bus, const char* topic, subscriber_callback_t callback) {    unsigned int index = hash(topic) % bus->bucket_count;    TopicEntry* entry = bus->buckets[index];    // 查找是否已存在该主题    while (entry) {        if (strcmp(entry->topic_name, topic) == 0) {            // 添加新订阅者到链表末尾            SubscriberNode* new_node = (SubscriberNode*)malloc(sizeof(SubscriberNode));            new_node->callback = callback;            new_node->next = NULL;            if (entry->subscribers == NULL) {                entry->subscribers = new_node;            } else {                SubscriberNode* tail = entry->subscribers;                while (tail->next) tail = tail->next;                tail->next = new_node;            }            return;        }        entry = entry->next;    }    // 主题不存在,创建新条目    TopicEntry* new_entry = (TopicEntry*)malloc(sizeof(TopicEntry));    new_entry->topic_name = strdup(topic);    new_entry->subscribers = NULL;    new_entry->next = bus->buckets[index];    bus->buckets[index] = new_entry;    // 添加第一个订阅者    SubscriberNode* new_node = (SubscriberNode*)malloc(sizeof(SubscriberNode));    new_node->callback = callback;    new_node->next = NULL;    new_entry->subscribers = new_node;}

3. 发布消息

void event_bus_publish(EventBus* bus, const char* topic, const void* data) {    unsigned int index = hash(topic) % bus->bucket_count;    TopicEntry* entry = bus->buckets[index];    while (entry) {        if (strcmp(entry->topic_name, topic) == 0) {            SubscriberNode* sub = entry->subscribers;            while (sub) {                sub->callback(topic, data);                sub = sub->next;            }            break;        }        entry = entry->next;    }}

四、完整使用示例

下面是一个完整的测试程序,演示如何使用我们构建的 消息传递机制C语言 实现:

void on_temperature_update(const char* topic, const void* data) {    float temp = *(const float*)data;    printf("[温度传感器] 收到更新: %.2f°C\n", temp);}void on_log_message(const char* topic, const void* data) {    printf("[日志模块] 收到消息: %s\n", (const char*)data);}int main() {    EventBus* bus = event_bus_create();    // 订阅主题    event_bus_subscribe(bus, "sensor/temperature", on_temperature_update);    event_bus_subscribe(bus, "system/log", on_log_message);    // 发布消息    float temp = 25.6f;    event_bus_publish(bus, "sensor/temperature", &temp);    const char* msg = "系统启动成功!";    event_bus_publish(bus, "system/log", msg);    // 注意:实际项目中应添加内存释放函数    return 0;}

五、总结与扩展

通过以上代码,我们成功在 C 语言中实现了基本的 观察者模式C实现。这个系统具有以下优点:

  • 解耦发布者与订阅者
  • 支持多个订阅者监听同一主题
  • 易于扩展(可增加取消订阅、通配符主题等功能)

对于嵌入式或资源受限环境,你可以简化哈希表,改用线性查找;也可以加入线程安全机制(如互斥锁)以支持多线程场景。

掌握 C语言发布订阅模式 不仅能提升你的架构设计能力,还能为学习更复杂的 事件驱动编程C语言 框架打下坚实基础。快动手试试吧!