嵌入式Linux下如何实现web服务器与本地C应用的数据交互
实现方案整体思路
thttpd原生支持CGI程序,你可以通过CGI作为中间层完成web前端和本地C串口应用的通信,配合HTTP短轮询即可实现串口返回数据的页面实时刷新,整个方案资源占用极低,非常适配嵌入式Linux场景。
具体实现步骤
1. 选定进程间通信方式
本地UART C应用和CGI是两个独立进程,选以下任意一种简单方案即可:
- 命名管道(FIFO):实现难度最低,单向读写就能满足需求,资源占用极小,嵌入式场景优先选这个
- Unix域套接字:支持全双工通信,后续要扩展功能的话更灵活
2. 改造现有UART C应用
在原有串口处理逻辑的基础上增加通信监听逻辑即可:
- 启动时创建两个命名管道,分别用于串口发送、接收方向的数据传输,可以直接调用
mkfifo()函数实现,也可以启动脚本里先执行mkfifo /tmp/uart_tx_fifo 0666和mkfifo /tmp/uart_rx_fifo 0666 - 开独立线程监听发送管道的读端,收到数据后直接调用现有串口发送函数写入UART
- 开另一个独立线程监听UART读端,收到串口返回的数据后写入接收管道,或者直接写入临时文件缓存也可以
核心代码示例:
#include <stdio.h> #include <fcntl.h> #include <unistd.h> #include <sys/stat.h> // 你现有串口操作函数的声明 extern int uart_send(char *buf, int len); extern int uart_recv(char *buf, int len); int main(void) { // 创建命名管道 mkfifo("/tmp/uart_tx_fifo", 0666); mkfifo("/tmp/uart_rx_fifo", 0666); // 监听发送管道,转发数据到串口 int tx_fd = open("/tmp/uart_tx_fifo", O_RDONLY); char tx_buf[256] = {0}; while(1) { int rx_len = read(tx_fd, tx_buf, sizeof(tx_buf)); if(rx_len > 0) { uart_send(tx_buf, rx_len); memset(tx_buf, 0, sizeof(tx_buf)); } } // 监听串口,转发返回数据到接收管道 int rx_fd = open("/tmp/uart_rx_fifo", O_WRONLY); char rx_buf[256] = {0}; while(1) { int recv_len = uart_recv(rx_buf, sizeof(rx_buf)); if(recv_len > 0) { write(rx_fd, rx_buf, recv_len); memset(rx_buf, 0, sizeof(rx_buf)); } } return 0; }
3. 编写CGI程序对接thttpd
thttpd默认支持CGI,把编译好的CGI程序放到配置的cgi-bin目录下即可:
处理表单提交的CGI(uart_send.cgi)
负责解析前端表单提交的数据,写入发送管道:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <unistd.h> int main(void) { char *content_len = getenv("CONTENT_LENGTH"); int len = atoi(content_len); char req_buf[256] = {0}; fread(req_buf, 1, len, stdin); // 解析表单字段,假设表单输入框的name属性为uart_data char *uart_data = strstr(req_buf, "uart_data=") + 9; // 处理URL编码的话可以自己加解码逻辑,纯ASCII字符可以直接传输 int fd = open("/tmp/uart_tx_fifo", O_WRONLY); write(fd, uart_data, strlen(uart_data)); close(fd); // 返回HTTP响应 printf("Content-Type: text/plain\r\n\r\n"); printf("ok"); return 0; }
读取串口返回数据的CGI(uart_recv.cgi)
负责读取接收管道的内容,返回给前端:
#include <stdio.h> #include <fcntl.h> #include <unistd.h> int main(void) { int fd = open("/tmp/uart_rx_fifo", O_RDONLY | O_NONBLOCK); char buf[256] = {0}; int len = read(fd, buf, sizeof(buf)); close(fd); printf("Content-Type: text/plain\r\n\r\n"); if(len > 0) printf("%s", buf); else printf(""); return 0; }
4. 编写前端页面
- 写一个POST表单,提交地址指向
/cgi-bin/uart_send.cgi,输入框name设置为uart_data - 前端加JS定时器,每隔1-2秒请求一次
/cgi-bin/uart_recv.cgi,拿到返回值后更新页面DOM,就可以实现数据实时刷新的效果
5. 配置注意事项
- 给两个命名管道设置
0666权限,避免thttpd运行用户没有读写权限 - 如果thttpd默认没开启CGI,启动时加上参数
-c /cgi-bin/*即可,指定该目录下的所有文件按CGI程序执行 cgi-bin目录要给thttpd运行用户开放执行权限
内容的提问来源于stack exchange,提问作者AlexB
相关产品推荐
相关产品推荐

