383 lines
14 KiB
HTML
383 lines
14 KiB
HTML
![]() |
<!DOCTYPE html>
|
|||
|
<html lang="zh-CN">
|
|||
|
<head>
|
|||
|
<meta charset="UTF-8">
|
|||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|||
|
<title>前端WebSocket连接示例</title>
|
|||
|
<script src="https://cdn.socket.io/4.7.2/socket.io.min.js"></script>
|
|||
|
<style>
|
|||
|
body {
|
|||
|
font-family: Arial, sans-serif;
|
|||
|
max-width: 800px;
|
|||
|
margin: 0 auto;
|
|||
|
padding: 20px;
|
|||
|
background-color: #f5f5f5;
|
|||
|
}
|
|||
|
.container {
|
|||
|
background: white;
|
|||
|
padding: 20px;
|
|||
|
border-radius: 8px;
|
|||
|
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
|||
|
}
|
|||
|
.status {
|
|||
|
padding: 10px;
|
|||
|
margin: 10px 0;
|
|||
|
border-radius: 4px;
|
|||
|
font-weight: bold;
|
|||
|
}
|
|||
|
.connected { background-color: #d4edda; color: #155724; }
|
|||
|
.disconnected { background-color: #f8d7da; color: #721c24; }
|
|||
|
.error { background-color: #fff3cd; color: #856404; }
|
|||
|
button {
|
|||
|
background-color: #007bff;
|
|||
|
color: white;
|
|||
|
border: none;
|
|||
|
padding: 10px 20px;
|
|||
|
margin: 5px;
|
|||
|
border-radius: 4px;
|
|||
|
cursor: pointer;
|
|||
|
}
|
|||
|
button:hover { background-color: #0056b3; }
|
|||
|
button:disabled {
|
|||
|
background-color: #6c757d;
|
|||
|
cursor: not-allowed;
|
|||
|
}
|
|||
|
#videoContainer {
|
|||
|
margin-top: 20px;
|
|||
|
text-align: center;
|
|||
|
}
|
|||
|
#rtspImage {
|
|||
|
max-width: 100%;
|
|||
|
height: auto;
|
|||
|
border: 2px solid #ddd;
|
|||
|
border-radius: 4px;
|
|||
|
}
|
|||
|
.log {
|
|||
|
background-color: #f8f9fa;
|
|||
|
border: 1px solid #dee2e6;
|
|||
|
border-radius: 4px;
|
|||
|
padding: 10px;
|
|||
|
margin-top: 20px;
|
|||
|
height: 200px;
|
|||
|
overflow-y: auto;
|
|||
|
font-family: monospace;
|
|||
|
font-size: 12px;
|
|||
|
}
|
|||
|
</style>
|
|||
|
</head>
|
|||
|
<body>
|
|||
|
<div class="container">
|
|||
|
<h1>前端WebSocket连接示例</h1>
|
|||
|
|
|||
|
<div id="status" class="status disconnected">未连接</div>
|
|||
|
|
|||
|
<div>
|
|||
|
<button id="connectBtn" onclick="connectWebSocket()">连接WebSocket</button>
|
|||
|
<button id="disconnectBtn" onclick="disconnectWebSocket()" disabled>断开连接</button>
|
|||
|
<button id="startRtspBtn" onclick="startRtsp()" disabled>启动RTSP</button>
|
|||
|
<button id="stopRtspBtn" onclick="stopRtsp()" disabled>停止RTSP</button>
|
|||
|
</div>
|
|||
|
|
|||
|
<div style="margin-top: 10px;">
|
|||
|
<button onclick="checkBackendStatus()">检查后端状态</button>
|
|||
|
<button onclick="testSocketConnection()">测试Socket连接</button>
|
|||
|
<button onclick="clearLog()">清空日志</button>
|
|||
|
<button onclick="showDebugInfo()">显示调试信息</button>
|
|||
|
</div>
|
|||
|
|
|||
|
<div id="debugInfo" style="display: none; margin-top: 10px; padding: 10px; background-color: #e9ecef; border-radius: 4px;">
|
|||
|
<h4>调试信息</h4>
|
|||
|
<div id="debugContent"></div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div id="videoContainer">
|
|||
|
<h3>RTSP视频流</h3>
|
|||
|
<img id="rtspImage" src="" alt="RTSP视频流" style="display: none;">
|
|||
|
<div id="noVideo">暂无视频流</div>
|
|||
|
</div>
|
|||
|
|
|||
|
<div class="log" id="logContainer"></div>
|
|||
|
</div>
|
|||
|
|
|||
|
<script>
|
|||
|
let socket = null;
|
|||
|
let frameCount = 0;
|
|||
|
|
|||
|
// 后端服务器地址配置
|
|||
|
const BACKEND_URL = 'http://localhost:5000'; // 根据实际情况修改
|
|||
|
// 如果是远程服务器,使用: 'http://192.168.1.173:5000'
|
|||
|
|
|||
|
function log(message) {
|
|||
|
const logContainer = document.getElementById('logContainer');
|
|||
|
const timestamp = new Date().toLocaleTimeString();
|
|||
|
logContainer.innerHTML += `[${timestamp}] ${message}<br>`;
|
|||
|
logContainer.scrollTop = logContainer.scrollHeight;
|
|||
|
}
|
|||
|
|
|||
|
function updateStatus(status, className) {
|
|||
|
const statusEl = document.getElementById('status');
|
|||
|
statusEl.textContent = status;
|
|||
|
statusEl.className = `status ${className}`;
|
|||
|
}
|
|||
|
|
|||
|
function updateButtons(connected, rtspRunning = false) {
|
|||
|
document.getElementById('connectBtn').disabled = connected;
|
|||
|
document.getElementById('disconnectBtn').disabled = !connected;
|
|||
|
document.getElementById('startRtspBtn').disabled = !connected || rtspRunning;
|
|||
|
document.getElementById('stopRtspBtn').disabled = !connected || !rtspRunning;
|
|||
|
}
|
|||
|
|
|||
|
function connectWebSocket() {
|
|||
|
try {
|
|||
|
log('正在连接到 ' + BACKEND_URL);
|
|||
|
|
|||
|
// 创建Socket.IO连接
|
|||
|
socket = io(BACKEND_URL, {
|
|||
|
transports: ['websocket', 'polling'],
|
|||
|
timeout: 10000,
|
|||
|
forceNew: true
|
|||
|
});
|
|||
|
|
|||
|
// 连接成功事件
|
|||
|
socket.on('connect', () => {
|
|||
|
log('✅ WebSocket连接成功!Socket ID: ' + socket.id);
|
|||
|
log('🔍 连接详情: ' + JSON.stringify({
|
|||
|
connected: socket.connected,
|
|||
|
id: socket.id,
|
|||
|
transport: socket.io.engine.transport.name
|
|||
|
}));
|
|||
|
updateStatus('已连接', 'connected');
|
|||
|
updateButtons(true);
|
|||
|
});
|
|||
|
|
|||
|
// 连接失败事件
|
|||
|
socket.on('connect_error', (error) => {
|
|||
|
log('❌ 连接失败: ' + error.message);
|
|||
|
log('🔍 错误详情: ' + JSON.stringify(error));
|
|||
|
updateStatus('连接失败', 'error');
|
|||
|
updateButtons(false);
|
|||
|
});
|
|||
|
|
|||
|
// 断开连接事件
|
|||
|
socket.on('disconnect', (reason) => {
|
|||
|
log('⚠️ 连接断开: ' + reason);
|
|||
|
updateStatus('已断开', 'disconnected');
|
|||
|
updateButtons(false);
|
|||
|
hideVideo();
|
|||
|
});
|
|||
|
|
|||
|
// 监听所有事件(调试用)
|
|||
|
socket.onAny((eventName, ...args) => {
|
|||
|
log(`📨 收到事件: ${eventName}, 数据: ${JSON.stringify(args)}`);
|
|||
|
});
|
|||
|
|
|||
|
// 监听RTSP状态事件
|
|||
|
socket.on('rtsp_status', (data) => {
|
|||
|
log('📺 RTSP状态: ' + JSON.stringify(data));
|
|||
|
if (data.status === 'started') {
|
|||
|
updateButtons(true, true);
|
|||
|
} else if (data.status === 'stopped') {
|
|||
|
updateButtons(true, false);
|
|||
|
hideVideo();
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// 监听RTSP帧数据
|
|||
|
socket.on('rtsp_frame', (data) => {
|
|||
|
if (data.image) {
|
|||
|
frameCount++;
|
|||
|
displayFrame(data.image);
|
|||
|
if (frameCount % 30 === 0) { // 每30帧记录一次
|
|||
|
log(`🎬 已接收 ${frameCount} 帧`);
|
|||
|
}
|
|||
|
} else {
|
|||
|
log('⚠️ 收到rtsp_frame事件但无图像数据: ' + JSON.stringify(data));
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
// 监听错误事件
|
|||
|
socket.on('error', (error) => {
|
|||
|
log('❌ Socket错误: ' + JSON.stringify(error));
|
|||
|
});
|
|||
|
|
|||
|
} catch (error) {
|
|||
|
log('💥 连接异常: ' + error.message);
|
|||
|
log('🔍 异常堆栈: ' + error.stack);
|
|||
|
updateStatus('连接异常', 'error');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function disconnectWebSocket() {
|
|||
|
if (socket) {
|
|||
|
socket.disconnect();
|
|||
|
socket = null;
|
|||
|
log('主动断开连接');
|
|||
|
updateStatus('已断开', 'disconnected');
|
|||
|
updateButtons(false);
|
|||
|
hideVideo();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function startRtsp() {
|
|||
|
if (socket && socket.connected) {
|
|||
|
log('🚀 发送start_rtsp事件');
|
|||
|
log('🔍 Socket状态: ' + JSON.stringify({
|
|||
|
connected: socket.connected,
|
|||
|
id: socket.id,
|
|||
|
transport: socket.io.engine.transport.name
|
|||
|
}));
|
|||
|
|
|||
|
// 发送事件并监听确认
|
|||
|
socket.emit('start_rtsp', {}, (ack) => {
|
|||
|
if (ack) {
|
|||
|
log('✅ start_rtsp事件已确认: ' + JSON.stringify(ack));
|
|||
|
} else {
|
|||
|
log('⚠️ start_rtsp事件无确认响应');
|
|||
|
}
|
|||
|
});
|
|||
|
|
|||
|
frameCount = 0;
|
|||
|
|
|||
|
// 设置超时检查
|
|||
|
setTimeout(() => {
|
|||
|
if (frameCount === 0) {
|
|||
|
log('⏰ 5秒后仍未收到视频帧,可能存在问题');
|
|||
|
checkBackendStatus();
|
|||
|
}
|
|||
|
}, 5000);
|
|||
|
|
|||
|
} else {
|
|||
|
log('❌ WebSocket未连接,无法启动RTSP');
|
|||
|
log('🔍 Socket状态: ' + (socket ? '存在但未连接' : '不存在'));
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function stopRtsp() {
|
|||
|
if (socket && socket.connected) {
|
|||
|
log('🛑 发送stop_rtsp事件');
|
|||
|
socket.emit('stop_rtsp', {}, (ack) => {
|
|||
|
if (ack) {
|
|||
|
log('✅ stop_rtsp事件已确认: ' + JSON.stringify(ack));
|
|||
|
} else {
|
|||
|
log('⚠️ stop_rtsp事件无确认响应');
|
|||
|
}
|
|||
|
});
|
|||
|
} else {
|
|||
|
log('❌ WebSocket未连接,无法停止RTSP');
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
function displayFrame(base64Image) {
|
|||
|
const img = document.getElementById('rtspImage');
|
|||
|
const noVideo = document.getElementById('noVideo');
|
|||
|
|
|||
|
img.src = 'data:image/jpeg;base64,' + base64Image;
|
|||
|
img.style.display = 'block';
|
|||
|
noVideo.style.display = 'none';
|
|||
|
}
|
|||
|
|
|||
|
function hideVideo() {
|
|||
|
const img = document.getElementById('rtspImage');
|
|||
|
const noVideo = document.getElementById('noVideo');
|
|||
|
|
|||
|
img.style.display = 'none';
|
|||
|
img.src = '';
|
|||
|
noVideo.style.display = 'block';
|
|||
|
}
|
|||
|
|
|||
|
// 检查后端服务状态
|
|||
|
function checkBackendStatus() {
|
|||
|
log('🔍 检查后端服务状态...');
|
|||
|
|
|||
|
fetch(BACKEND_URL + '/health')
|
|||
|
.then(response => {
|
|||
|
if (response.ok) {
|
|||
|
log('✅ 后端HTTP服务正常');
|
|||
|
return response.text();
|
|||
|
} else {
|
|||
|
log('⚠️ 后端HTTP服务响应异常: ' + response.status);
|
|||
|
}
|
|||
|
})
|
|||
|
.then(data => {
|
|||
|
if (data) {
|
|||
|
log('📄 后端响应: ' + data);
|
|||
|
}
|
|||
|
})
|
|||
|
.catch(error => {
|
|||
|
log('❌ 无法连接到后端服务: ' + error.message);
|
|||
|
log('💡 请检查后端服务是否已启动,地址是否正确');
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// 测试Socket.IO连接
|
|||
|
function testSocketConnection() {
|
|||
|
log('🧪 测试Socket.IO连接...');
|
|||
|
|
|||
|
const testSocket = io(BACKEND_URL + '/socket.io/', {
|
|||
|
transports: ['polling'],
|
|||
|
timeout: 5000
|
|||
|
});
|
|||
|
|
|||
|
testSocket.on('connect', () => {
|
|||
|
log('✅ Socket.IO测试连接成功');
|
|||
|
testSocket.disconnect();
|
|||
|
});
|
|||
|
|
|||
|
testSocket.on('connect_error', (error) => {
|
|||
|
log('❌ Socket.IO测试连接失败: ' + error.message);
|
|||
|
});
|
|||
|
}
|
|||
|
|
|||
|
// 清空日志
|
|||
|
function clearLog() {
|
|||
|
document.getElementById('logContainer').innerHTML = '';
|
|||
|
log('🧹 日志已清空');
|
|||
|
}
|
|||
|
|
|||
|
// 显示调试信息
|
|||
|
function showDebugInfo() {
|
|||
|
const debugInfo = document.getElementById('debugInfo');
|
|||
|
const debugContent = document.getElementById('debugContent');
|
|||
|
|
|||
|
let info = '<strong>当前状态:</strong><br>';
|
|||
|
info += `Socket对象: ${socket ? '存在' : '不存在'}<br>`;
|
|||
|
|
|||
|
if (socket) {
|
|||
|
info += `连接状态: ${socket.connected ? '已连接' : '未连接'}<br>`;
|
|||
|
info += `Socket ID: ${socket.id || '无'}<br>`;
|
|||
|
info += `传输方式: ${socket.io?.engine?.transport?.name || '未知'}<br>`;
|
|||
|
info += `URL: ${socket.io?.uri || '未知'}<br>`;
|
|||
|
}
|
|||
|
|
|||
|
info += `<br><strong>配置信息:</strong><br>`;
|
|||
|
info += `后端地址: ${BACKEND_URL}<br>`;
|
|||
|
info += `接收帧数: ${frameCount}<br>`;
|
|||
|
info += `页面URL: ${window.location.href}<br>`;
|
|||
|
info += `用户代理: ${navigator.userAgent}<br>`;
|
|||
|
|
|||
|
debugContent.innerHTML = info;
|
|||
|
debugInfo.style.display = debugInfo.style.display === 'none' ? 'block' : 'none';
|
|||
|
}
|
|||
|
|
|||
|
// 页面加载完成后的初始化
|
|||
|
window.onload = function() {
|
|||
|
log('📄 页面加载完成,可以开始连接WebSocket');
|
|||
|
log('🌐 后端地址: ' + BACKEND_URL);
|
|||
|
log('⚠️ 请确保后端服务已启动');
|
|||
|
|
|||
|
// 自动检查后端状态
|
|||
|
setTimeout(() => {
|
|||
|
checkBackendStatus();
|
|||
|
testSocketConnection();
|
|||
|
}, 1000);
|
|||
|
};
|
|||
|
|
|||
|
// 页面关闭时清理连接
|
|||
|
window.onbeforeunload = function() {
|
|||
|
if (socket) {
|
|||
|
socket.disconnect();
|
|||
|
}
|
|||
|
};
|
|||
|
</script>
|
|||
|
</body>
|
|||
|
</html>
|