Linux 监控系统 视频捕获模块 改为多进程,主进程采集、压缩、传输视频,另外一个线程接收指令 代码
时间: 2024-01-24 08:17:31 浏览: 128
嵌入式linux下多线程视频监控的设计和实现
将视频捕获模块改为多进程的实现方式,可以增强程序的稳定性和可靠性,同时也能提高程序的运行效率。下面是一种可能的实现方式:
```c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/wait.h>
#define DEFAULT_PORT 8000 // 默认端口号
#define BUF_SIZE 4096 // 缓冲区大小
int sockfd, connfd; // 套接字描述符
pid_t pid; // 子进程 ID
int pipe_fd[2]; // 管道文件描述符
char recv_buf[BUF_SIZE], send_buf[BUF_SIZE]; // 接收缓冲区和发送缓冲区
void sig_handler(int signo)
{
if (signo == SIGINT) {
printf("Server is closed.\n");
close(sockfd);
exit(1);
}
}
void child_process()
{
close(pipe_fd[0]); // 关闭管道读端
int fd = open("/dev/video0", O_RDONLY); // 打开视频设备
if (fd == -1) {
perror("open video device failed");
exit(1);
}
while (1) {
// 从视频设备中读取数据
char buf[BUF_SIZE];
int n = read(fd, buf, BUF_SIZE);
if (n == -1) {
perror("read video device failed");
exit(1);
}
// 压缩视频数据
// ...
// 发送压缩后的视频数据
n = send(connfd, buf, n, 0);
if (n == -1) {
perror("send data failed");
exit(1);
}
}
close(fd); // 关闭视频设备文件描述符
close(connfd); // 关闭连接套接字
close(pipe_fd[1]); // 关闭管道写端
}
void parent_process()
{
close(pipe_fd[1]); // 关闭管道写端
while (1) {
// 接收命令
int n = recv(connfd, recv_buf, BUF_SIZE, 0);
if (n == -1) {
perror("receive data failed");
exit(1);
} else if (n == 0) {
printf("Client closed the connection.\n");
break;
}
// 处理命令
// ...
// 发送处理结果
n = send(connfd, send_buf, strlen(send_buf), 0);
if (n == -1) {
perror("send data failed");
exit(1);
}
}
close(connfd); // 关闭连接套接字
close(pipe_fd[0]); // 关闭管道读端
}
int main(int argc, char *argv[])
{
// 创建套接字
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == -1) {
perror("create socket failed");
exit(1);
}
// 绑定端口号
struct sockaddr_in server_addr;
memset(&server_addr, 0, sizeof(server_addr));
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(DEFAULT_PORT);
server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
if (bind(sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)) == -1) {
perror("bind socket failed");
exit(1);
}
// 监听套接字
if (listen(sockfd, 5) == -1) {
perror("listen socket failed");
exit(1);
}
// 设置信号处理函数
signal(SIGINT, sig_handler);
// 等待客户端连接
struct sockaddr_in client_addr;
socklen_t client_addr_len = sizeof(client_addr);
connfd = accept(sockfd, (struct sockaddr *)&client_addr, &client_addr_len);
if (connfd == -1) {
perror("accept client failed");
exit(1);
}
// 创建管道
if (pipe(pipe_fd) == -1) {
perror("create pipe failed");
exit(1);
}
// 创建子进程
pid = fork();
if (pid == -1) {
perror("create child process failed");
exit(1);
} else if (pid == 0) {
// 子进程
child_process();
} else {
// 父进程
parent_process();
}
// 等待子进程退出
wait(NULL);
return 0;
}
```
上述代码中,程序首先创建套接字并绑定端口号,然后等待客户端连接。连接建立后,程序创建一个管道,然后 fork 出一个子进程和一个父进程。子进程负责从视频设备中读取数据并发送给客户端,父进程负责接收客户端发送的命令并处理。子进程和父进程之间通过管道进行通信。
在子进程中,程序首先打开视频设备文件,并进入循环,不断从该设备中读取视频数据。读取到数据后,程序对其进行压缩(这里省略了具体实现),然后通过连接套接字发送给客户端。如果发送失败,程序将退出。
在父进程中,程序进入循环,不断接收客户端发送的命令。接收到命令后,程序对命令进行处理,并将处理结果通过连接套接字发送给客户端。如果发送失败,程序将退出。
子进程和父进程之间通过管道进行通信。在子进程中,程序关闭管道读端,只需要向管道写端写入数据即可发送给父进程。在父进程中,程序关闭管道写端,只需要从管道读端读取数据即可接收子进程发送的数据。
在程序运行过程中,如果接收到 SIGINT 信号(即 Ctrl+C),程序将关闭套接字并退出。
需要注意的是,上述代码中只是一种可能的实现方式,实际应用中可能需要根据具体情况进行适当修改。例如,程序在接收命令时可能需要进行解析,并根据解析结果执行相应的操作。此外,程序还需要进行错误处理,例如在打开视频设备或创建套接字时出现错误需要进行处理。
阅读全文