164 lines
3.9 KiB
C
164 lines
3.9 KiB
C
|
|
#include <stdio.h>
|
|||
|
|
#include <stdlib.h>
|
|||
|
|
#include <string.h>
|
|||
|
|
#include <unistd.h>
|
|||
|
|
#include <fcntl.h>
|
|||
|
|
#include <time.h>
|
|||
|
|
#include <arpa/inet.h>
|
|||
|
|
#include <sys/socket.h>
|
|||
|
|
#include <signal.h>
|
|||
|
|
#include <sys/wait.h>
|
|||
|
|
|
|||
|
|
#define PORT 9999
|
|||
|
|
#define TIMEOUT 3
|
|||
|
|
|
|||
|
|
pid_t play_pid = 0;
|
|||
|
|
|
|||
|
|
// 启动播放
|
|||
|
|
void start_playback()
|
|||
|
|
{
|
|||
|
|
if (play_pid == 0)
|
|||
|
|
{
|
|||
|
|
play_pid = fork();
|
|||
|
|
if (play_pid == 0)
|
|||
|
|
{
|
|||
|
|
execl("./audio_play", "./audio_play", NULL);
|
|||
|
|
perror("execl failed");
|
|||
|
|
exit(1);
|
|||
|
|
}
|
|||
|
|
printf("播放进程已启动,PID=%d\n", play_pid);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 停止播放
|
|||
|
|
void stop_playback()
|
|||
|
|
{
|
|||
|
|
if (play_pid > 0)
|
|||
|
|
{
|
|||
|
|
printf("停止播放,终止 PID=%d\n", play_pid);
|
|||
|
|
kill(play_pid, SIGTERM);
|
|||
|
|
waitpid(play_pid, NULL, 0);
|
|||
|
|
play_pid = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int main()
|
|||
|
|
{
|
|||
|
|
int listen_fd, conn_fd;
|
|||
|
|
struct sockaddr_in addr;
|
|||
|
|
char buffer[128];
|
|||
|
|
time_t last_time = 0;
|
|||
|
|
int playing = 0;
|
|||
|
|
fd_set read_fds;
|
|||
|
|
struct timeval tv;
|
|||
|
|
|
|||
|
|
listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
|||
|
|
if (listen_fd < 0)
|
|||
|
|
{
|
|||
|
|
perror("socket error");
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int opt = 1;
|
|||
|
|
setsockopt(listen_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
|
|||
|
|
|
|||
|
|
memset(&addr, 0, sizeof(addr));
|
|||
|
|
addr.sin_family = AF_INET;
|
|||
|
|
addr.sin_port = htons(PORT);
|
|||
|
|
addr.sin_addr.s_addr = htonl(INADDR_ANY);
|
|||
|
|
|
|||
|
|
if (bind(listen_fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
|
|||
|
|
{
|
|||
|
|
perror("bind error");
|
|||
|
|
close(listen_fd);
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (listen(listen_fd, 5) < 0)
|
|||
|
|
{
|
|||
|
|
perror("listen error");
|
|||
|
|
close(listen_fd);
|
|||
|
|
return 1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
printf("语音守护 TCP 服务器已启动,监听端口 %d...\n", PORT);
|
|||
|
|
|
|||
|
|
while (1)
|
|||
|
|
{
|
|||
|
|
printf("等待客户端连接...\n");
|
|||
|
|
conn_fd = accept(listen_fd, NULL, NULL);
|
|||
|
|
if (conn_fd < 0)
|
|||
|
|
{
|
|||
|
|
perror("accept error");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
printf("客户端已连接\n");
|
|||
|
|
|
|||
|
|
last_time = 0;
|
|||
|
|
playing = 0;
|
|||
|
|
|
|||
|
|
// 设置非阻塞模式
|
|||
|
|
fcntl(conn_fd, F_SETFL, O_NONBLOCK);
|
|||
|
|
|
|||
|
|
while (1)
|
|||
|
|
{
|
|||
|
|
FD_ZERO(&read_fds);
|
|||
|
|
FD_SET(conn_fd, &read_fds);
|
|||
|
|
tv.tv_sec = 1;
|
|||
|
|
tv.tv_usec = 0;
|
|||
|
|
|
|||
|
|
int ret = select(conn_fd + 1, &read_fds, NULL, NULL, &tv);
|
|||
|
|
if (ret > 0 && FD_ISSET(conn_fd, &read_fds))
|
|||
|
|
{
|
|||
|
|
ssize_t len = read(conn_fd, buffer, sizeof(buffer) - 1);
|
|||
|
|
if (len > 0)
|
|||
|
|
{
|
|||
|
|
buffer[len] = '\0';
|
|||
|
|
if (strstr(buffer, "RUNNING"))
|
|||
|
|
{
|
|||
|
|
last_time = time(NULL);
|
|||
|
|
if (!playing)
|
|||
|
|
{
|
|||
|
|
printf("收到心跳,启动播报...\n");
|
|||
|
|
start_playback();
|
|||
|
|
playing = 1;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (len == 0)
|
|||
|
|
{
|
|||
|
|
printf("客户端关闭连接\n");
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else if (ret == 0)
|
|||
|
|
{
|
|||
|
|
// 超时
|
|||
|
|
if (playing && (time(NULL) - last_time > TIMEOUT))
|
|||
|
|
{
|
|||
|
|
printf("超时未收到心跳,停止播报...\n");
|
|||
|
|
stop_playback();
|
|||
|
|
playing = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
perror("select error");
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
close(conn_fd);
|
|||
|
|
// 断开连接时停止播放
|
|||
|
|
if (playing)
|
|||
|
|
{
|
|||
|
|
printf("连接断开,停止播放\n");
|
|||
|
|
stop_playback();
|
|||
|
|
playing = 0;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
close(listen_fd);
|
|||
|
|
return 0;
|
|||
|
|
}
|