分布式系统与物联网架构及多线程应用解析
1. 安全套接字通信
在分布式系统和物联网架构中,安全套接字通信至关重要。wolfSSL 是一个强大的库,它为许多嵌入式操作系统提供了内置支持,能够适应不同的内存配置和套接字接口。它既可以集成到裸机系统中,与任何兼容的 TCP/IP 栈配合使用,也能通过基于回调的通用输入/输出(I/O)接口轻松适配。
在裸机或操作系统环境下,应用程序需要设计为访问安全套接层(SSL)来与远程系统通信,而 wolfSSL 库负责通过传输层提供安全通信通道的抽象。若要在现有的裸机 TCP/IP 实现之上集成 TLS 会话,wolfSSL 可以配置为非阻塞模式,轮询系统以获取套接字上接收到的新数据包,并由 TLS 层进行处理。
以下是使用 wolfSSL 创建基于 TCP 连接的 TLS 套接字的示例代码:
wolfSSL_Init();
wolfSSL_CTX *ctx;
ctx = wolfSSL_CTX_new(wolfTLSv1_2_server_method());
wolfSSL_SetIORecv(ctx, wolfssl_recv_cb);
wolfSSL_SetIOSend(ctx, wolfssl_send_cb);
其中,
wolfssl_recv_cb
和
wolfssl_send_cb
是两个回调函数,用于访问 TCP/IP 栈中的套接字通信。以下是这两个回调函数的实现示例:
int wolfssl_send_cb(WOLFSSL* ssl, char *buf, int sz, void *sk_ctx)
{
tcp_ip_socket *sk = (tcp_ip_socket *)sk_ctx;
int ret = tcp_socket_write(sk, buf, sz);
if (ret > 0)
return ret;
else
return WOLFSSL_CBIO_ERR_WANT_WRITE;
}
int wolfssl_recv_cb(WOLFSSL *ssl, char *buf, int sz, void *sk_ctx)
{
tcp_ip_socket *sk = (tcp_ip_socket *)sk_ctx;
int ret = tcp_socket_read(sk, buf, sz);
if (ret > 0)
return ret;
else
return WOLFSSL_CBIO_ERR_WANT_READ;
}
对于大多数常用的操作系统和 TCP/IP 栈 API,wolfSSL 已经提供了默认的 I/O 回调函数,因此只要激活正确的配置选项,就无需实现自定义回调函数。
在启动任何通信之前,与每个连接的 SSL 对象关联的 wolfSSL_CTX 对象必须配备一组证书和密钥。在复杂系统中,证书和密钥可以存储在文件系统中;而在嵌入式系统中,由于通常不支持文件系统,证书和密钥可以存储在内存中,并使用指向其内存位置的指针加载到上下文中:
wolfSSL_CTX_use_certificate_buffer(ctx, certificate, len, SSL_FILETYPE_ASN1);
wolfSSL_CTX_use_PrivateKey_buffer(ctx, key, len,SSL_FILETYPE_ASN1 );
2. 应用协议
在分布式场景中,嵌入式系统需要实现标准协议以与远程设备和云服务器进行通信。常见的远程服务设计方法主要有两种:
-
基于 Web 的服务
:这是一种经典的客户端 - 服务器、基于表征状态转移(REST)的通信方式,在通过个人计算机或便携式设备访问的 Web 服务中很流行。Web 服务在云端无需进行特殊适配来支持嵌入式系统,只需选择适合嵌入式设备的密码套件。不过,请求 - 回复通信模型对分布式应用的设计有一定限制。HTTP 协议可以通过双方协商升级,支持 WebSocket 协议,该协议在 HTTP 服务之上提供了对称、双向通道的抽象。
-
消息协议
:这种方法更能反映传感器或执行器嵌入式系统的功能,通过短二进制消息交换信息,这些消息可以由中间代理中继,并从服务器节点收集或分发。当网络中包含较小的节点时,消息协议是首选,因为其数据表示更简单,与主要基于人类可读字符串的 Web 服务相比,减少了传输大小和内存占用。
无论是哪种方法,TLS 都应在基础设施和设备层面得到支持,以实现端到端加密和可靠的设备识别。明文认证和预共享密钥加密是过时的技术,不应成为现代分布式系统安全策略的一部分。
消息协议中,消息队列遥测传输(MQTT)协议是一个很好的例子。它采用发布 - 订阅模型,通过 TCP/IP 实现不同物理位置的嵌入式设备互连,已被广泛使用,并得到了多种云架构的支持。该协议依赖 TCP 与中央代理建立连接,代理将消息从发布者分发给订阅者。发布者针对特定主题(由 URI 描述)推送数据,订阅者在连接时可以过滤他们想要关注的主题,代理会选择性地转发匹配过滤条件的消息。不过,一些小型嵌入式设备的客户端库实现可能缺乏安全机制支持,MQTT 协议支持的明文密码认证机制并不安全,不应用于明文 TCP/IP 通信。根据标准,可以通过 TCP 端口 8883 建立 SSL 会话,wolfSSL 在其单独的 GPL 库 wolfMQTT 中提供了基于 TCP 的 SSL 会话的安全实现,该库默认提供安全的 MQTT 套接字连接,能够通过证书和公钥实现客户端和服务器认证,并通过已建立的会话提供对称密钥加密。
REST 是 Roy Fielding 提出的术语,用于描述 Web 服务使用无状态协议与远程系统通信的模式。在符合 REST 的系统中,资源以针对特定 URI 的 HTTP 请求形式进行访问,使用与通过远程浏览器请求获取网页相同的协议栈。REST 请求实际上是扩展的 HTTP 请求,将所有数据表示为编码字符串,通过 TCP 在可读的 HTTP 流中传输。采用这种模式在服务器端具有许多架构优势,能够构建具有高可扩展性的分布式系统。虽然 REST 模式效率不高,且并非为嵌入式系统资源设计,但嵌入式系统可以通过实现简单的 REST 客户端与 RESTful 系统暴露的远程 Web 服务进行交互。
3. 分布式系统的单点故障
设计分布式系统时,需要考虑链路缺陷、无法访问的网关和其他故障。嵌入式设备在与互联网断开连接时不应停止工作,而应基于本地网关提供备用机制。以家庭中的智能家居系统为例,该系统用于控制所有供暖和制冷设备,可通过便携式设备访问并通过任何网络远程协调。温度传感器、加热器和冷却器通过嵌入式设备的网状网络进行控制,而中央控制则位于远程云服务器上。只要所有组件都连接到互联网,系统就能按预期工作。但在连接失败的情况下,用户将无法控制系统或激活任何功能。在局域网内的本地设备上终止应用服务可以确保在与互联网的链路出现故障以及任何阻止本地网络访问远程云设备的问题时,服务能够持续运行。如果有这样的机制,与互联网断开连接的系统仍然可以提供备用方案来访问传感器和执行器。此外,本地系统处理和转发设置与命令可以减少请求操作的延迟,因为请求无需通过互联网进行处理和转发。设计可靠的物联网网络必须仔细评估提供服务所使用的所有链路和设备中的单点故障,包括用于访问服务、消息代理和远程设备的骨干链路,这些都可能导致整个系统出现故障或其他问题。
4. 多线程应用
当系统复杂度增加,软件需要同时管理多个外设和事件时,依靠操作系统来协调和同步不同操作更为方便。将应用逻辑分离到不同线程中具有重要的架构优势。每个组件在其运行单元内执行设计好的操作,并在挂起、等待输入或超时事件时释放 CPU。
为了实现多线程嵌入式操作系统,我们可以开发一个针对参考平台的简约操作系统,逐步从头编写,提供一个工作调度器来并行运行多个任务。调度器的内部实现主要在系统服务调用中完成,其设计会影响系统的性能和其他特性,如不同的优先级级别和实时相关任务的时间约束。在示例代码中,将解释并实现一些不同上下文下的可能调度策略。
并行运行多个线程意味着资源可以共享,存在并发访问同一内存的可能性。大多数设计用于运行多线程系统的微处理器通过特定的汇编指令提供原语函数,以实现诸如信号量之类的锁定机制。示例操作系统将公开互斥锁和信号量原语,供线程用于控制对共享资源的访问。
通过引入内存保护机制,可以根据资源的地址对其进行分离,并让内核通过系统调用接口监督所有涉及硬件的操作。大多数实时嵌入式操作系统倾向于使用无分段的扁平模型,以保持内核代码尽可能小,并使用最小化的 API 来优化应用程序可用的资源。示例内核将展示如何创建一个系统调用 API,通过物理内存分段来保护内核、系统控制块、映射外设和其他任务的资源,从而提高系统的安全性。
通过上述对分布式系统与物联网架构以及多线程应用的介绍,我们可以看到在构建现代嵌入式系统时,需要综合考虑安全、通信协议、故障处理和多线程等多个方面,以实现高效、可靠和安全的系统。
5. 多线程实现的具体机制
5.1 调度器的设计与实现
调度器是多线程操作系统的核心组件,它负责决定哪个线程在何时运行。在我们开发的简约操作系统中,调度器的设计会影响系统各方面的性能。
以下是一个简单的调度器设计流程 mermaid 图:
graph TD
A[初始化] --> B[创建任务队列]
B --> C[任务添加到队列]
C --> D{是否有任务就绪}
D -- 是 --> E[选择任务执行]
E --> F[任务执行]
F --> G{任务是否完成}
G -- 是 --> H[从队列移除任务]
G -- 否 --> D
D -- 否 --> I[等待任务就绪]
I --> D
在代码实现方面,调度器的核心逻辑通常在系统服务调用中完成。例如,当一个任务完成或被阻塞时,调度器会选择下一个就绪的任务来执行。以下是一个简化的调度器代码示例:
// 任务结构体
typedef struct {
void (*function)(); // 任务函数
int state; // 任务状态,0 表示就绪,1 表示运行,2 表示阻塞
} Task;
// 任务队列
Task task_queue[MAX_TASKS];
int task_count = 0;
// 调度函数
void scheduler() {
while (1) {
for (int i = 0; i < task_count; i++) {
if (task_queue[i].state == 0) { // 任务就绪
task_queue[i].state = 1; // 设置为运行状态
task_queue[i].function(); // 执行任务
task_queue[i].state = 0; // 任务完成,设置为就绪状态
}
}
}
}
5.2 内存保护机制
内存保护机制对于多线程系统的安全性至关重要。通过物理内存分段,我们可以保护内核、系统控制块、映射外设和其他任务的资源。
以下是一个简单的内存保护机制的实现步骤:
1.
定义内存区域
:将内存划分为不同的区域,例如内核空间、用户空间、外设映射空间等。
#define KERNEL_MEMORY_START 0x00000000
#define KERNEL_MEMORY_END 0x00100000
#define USER_MEMORY_START 0x00100000
#define USER_MEMORY_END 0x01000000
- 设置访问权限 :为每个内存区域设置不同的访问权限,例如内核空间只能由内核代码访问,用户空间可以由用户线程访问。
// 示例:设置内存区域的访问权限
void set_memory_permission(int start, int end, int permission) {
// 具体的权限设置代码,可能涉及硬件寄存器操作
}
- 检查访问权限 :在进行内存访问时,检查访问的地址是否在允许的范围内,并且是否具有相应的访问权限。
// 示例:检查内存访问权限
int check_memory_access(int address) {
if (address >= KERNEL_MEMORY_START && address < KERNEL_MEMORY_END) {
// 检查是否是内核代码访问
return is_kernel_code() ? 1 : 0;
} else if (address >= USER_MEMORY_START && address < USER_MEMORY_END) {
// 检查是否是用户线程访问
return is_user_thread() ? 1 : 0;
}
return 0;
}
6. 总结
本文全面介绍了分布式系统与物联网架构以及多线程应用的相关内容。在分布式系统和物联网架构中,安全套接字通信是基础,wolfSSL 库为实现安全的 TCP/IP 连接提供了强大的支持。通过合理配置和使用 wolfSSL,我们可以在嵌入式系统中实现高效、安全的通信。
应用协议方面,基于 Web 的服务和消息协议各有优缺点,开发者需要根据具体的应用场景选择合适的协议。TLS 作为一种重要的安全机制,应在基础设施和设备层面得到广泛应用,以确保端到端的加密和可靠的设备识别。
分布式系统的单点故障是一个不可忽视的问题,设计可靠的物联网网络需要仔细评估所有可能的单点故障,并提供相应的备用机制,以确保系统在各种情况下都能稳定运行。
多线程应用为处理复杂系统提供了有效的解决方案。通过开发调度器和引入内存保护机制,我们可以实现多个任务的并行运行,提高系统的性能和安全性。
在构建现代嵌入式系统时,我们需要综合考虑安全、通信协议、故障处理和多线程等多个方面,结合先进的技术和方法,以实现高效、可靠和安全的系统。未来,随着技术的不断发展,分布式系统和物联网架构以及多线程应用将在更多领域得到广泛应用,为我们的生活和工作带来更多的便利和创新。
超级会员免费看
286

被折叠的 条评论
为什么被折叠?



