first commit
This commit is contained in:
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
bin/
|
||||
obj/
|
||||
/packages/
|
||||
riderModule.iml
|
||||
/_ReSharper.Caches/
|
||||
23
Controllers/HeartRateController.cs
Normal file
23
Controllers/HeartRateController.cs
Normal file
@ -0,0 +1,23 @@
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using HikarinHeartRateMonitorService.Models;
|
||||
|
||||
namespace HikarinHeartRateMonitorService.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class HeartRateController : ControllerBase
|
||||
{
|
||||
private readonly ILogger<HeartRateController> _logger;
|
||||
|
||||
public HeartRateController(ILogger<HeartRateController> logger)
|
||||
{
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Get()
|
||||
{
|
||||
return Ok(new { Message = "心率监测WebSocket服务正在运行。请使用WebSocket连接到'/ws'路径。" });
|
||||
}
|
||||
}
|
||||
}
|
||||
14
HikarinHeartRateMonitorService.csproj
Normal file
14
HikarinHeartRateMonitorService.csproj
Normal file
@ -0,0 +1,14 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net9.0</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="9.0.2"/>
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.0"/>
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
6
HikarinHeartRateMonitorService.http
Normal file
6
HikarinHeartRateMonitorService.http
Normal file
@ -0,0 +1,6 @@
|
||||
@HikarinHeartRateMonitorService_HostAddress = http://localhost:5037
|
||||
|
||||
GET {{HikarinHeartRateMonitorService_HostAddress}}/weatherforecast/
|
||||
Accept: application/json
|
||||
|
||||
###
|
||||
16
HikarinHeartRateMonitorService.sln
Normal file
16
HikarinHeartRateMonitorService.sln
Normal file
@ -0,0 +1,16 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HikarinHeartRateMonitorService", "HikarinHeartRateMonitorService.csproj", "{81D483F5-853A-4614-9E01-F8121FDE8DAE}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{81D483F5-853A-4614-9E01-F8121FDE8DAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{81D483F5-853A-4614-9E01-F8121FDE8DAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{81D483F5-853A-4614-9E01-F8121FDE8DAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{81D483F5-853A-4614-9E01-F8121FDE8DAE}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
77
Middleware/WebSocketMiddleware.cs
Normal file
77
Middleware/WebSocketMiddleware.cs
Normal file
@ -0,0 +1,77 @@
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using HikarinHeartRateMonitorService.Services;
|
||||
using WebSocketManager = HikarinHeartRateMonitorService.Services.WebSocketManager;
|
||||
|
||||
namespace HikarinHeartRateMonitorService.Middleware
|
||||
{
|
||||
public class WebSocketMiddleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly WebSocketManager _webSocketManager;
|
||||
private readonly ILogger<WebSocketMiddleware> _logger;
|
||||
|
||||
public WebSocketMiddleware(RequestDelegate next, WebSocketManager webSocketManager,
|
||||
ILogger<WebSocketMiddleware> logger)
|
||||
{
|
||||
_next = next;
|
||||
_webSocketManager = webSocketManager;
|
||||
_logger = logger;
|
||||
}
|
||||
|
||||
public async Task InvokeAsync(HttpContext context)
|
||||
{
|
||||
if (!context.WebSockets.IsWebSocketRequest)
|
||||
{
|
||||
await _next(context);
|
||||
return;
|
||||
}
|
||||
|
||||
var socket = await context.WebSockets.AcceptWebSocketAsync();
|
||||
var socketId = Guid.NewGuid().ToString();
|
||||
|
||||
_webSocketManager.AddSocket(socketId, socket);
|
||||
_logger.LogInformation($"WebSocket连接已建立: {socketId}");
|
||||
|
||||
await ReceiveMessages(socketId, socket);
|
||||
}
|
||||
|
||||
private async Task ReceiveMessages(string socketId, WebSocket socket)
|
||||
{
|
||||
var buffer = new byte[4096];
|
||||
|
||||
try
|
||||
{
|
||||
while (socket.State == WebSocketState.Open)
|
||||
{
|
||||
var result = await socket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
|
||||
|
||||
if (result.MessageType == WebSocketMessageType.Text)
|
||||
{
|
||||
var message = Encoding.UTF8.GetString(buffer, 0, result.Count);
|
||||
await _webSocketManager.HandleMessageAsync(socketId, message);
|
||||
}
|
||||
else if (result.MessageType == WebSocketMessageType.Close)
|
||||
{
|
||||
await _webSocketManager.RemoveSocket(socketId);
|
||||
_logger.LogInformation($"WebSocket连接已关闭: {socketId}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, $"WebSocket处理时发生错误: {socketId}");
|
||||
await _webSocketManager.RemoveSocket(socketId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class WebSocketMiddlewareExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseHeartRateWebSockets(this IApplicationBuilder builder)
|
||||
{
|
||||
return builder.UseMiddleware<WebSocketMiddleware>();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
Models/HeartRateData.cs
Normal file
17
Models/HeartRateData.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace HikarinHeartRateMonitorService.Models
|
||||
{
|
||||
public class HeartRateData
|
||||
{
|
||||
public int HeartRate { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
public string DeviceName { get; set; }
|
||||
public readonly string Token = "1sZkzBKD3WpRT0eQ9Vk4";
|
||||
}
|
||||
|
||||
public class HeartRateResponse
|
||||
{
|
||||
public int HeartRate { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
public string DeviceName { get; set; }
|
||||
}
|
||||
}
|
||||
47
Program.cs
Normal file
47
Program.cs
Normal file
@ -0,0 +1,47 @@
|
||||
using HikarinHeartRateMonitorService.Middleware;
|
||||
using HikarinHeartRateMonitorService.Services;
|
||||
using WebSocketManager = HikarinHeartRateMonitorService.Services.WebSocketManager;
|
||||
var builder = WebApplication.CreateBuilder(args);
|
||||
|
||||
// Add services to the container.
|
||||
// Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
|
||||
builder.Services.AddOpenApi();
|
||||
|
||||
// 添加控制器支持
|
||||
builder.Services.AddControllers();
|
||||
|
||||
// 注册WebSocket管理器
|
||||
builder.Services.AddSingleton<WebSocketManager>();
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
// Configure the HTTP request pipeline.
|
||||
if (app.Environment.IsDevelopment())
|
||||
{
|
||||
app.MapOpenApi();
|
||||
}
|
||||
|
||||
app.UseHttpsRedirection();
|
||||
|
||||
// 添加WebSocket支持
|
||||
app.UseWebSockets(new WebSocketOptions
|
||||
{
|
||||
KeepAliveInterval = TimeSpan.FromMinutes(2),
|
||||
AllowedOrigins = { "*" } // 生产环境中请设置具体的允许来源
|
||||
});
|
||||
|
||||
// 使用自定义WebSocket中间件
|
||||
app.UseHeartRateWebSockets();
|
||||
|
||||
// 添加静态文件支持
|
||||
app.UseStaticFiles();
|
||||
|
||||
/*调试页面
|
||||
app.MapGet("/", async context => {
|
||||
context.Response.Redirect("/index.html");
|
||||
});
|
||||
*/
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
app.Run();
|
||||
23
Properties/launchSettings.json
Normal file
23
Properties/launchSettings.json
Normal file
@ -0,0 +1,23 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/launchsettings.json",
|
||||
"profiles": {
|
||||
"http": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "http://localhost:8081",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
},
|
||||
"https": {
|
||||
"commandName": "Project",
|
||||
"dotnetRunMessages": true,
|
||||
"launchBrowser": false,
|
||||
"applicationUrl": "https://localhost:7060;http://localhost:5037",
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
78
README.md
Normal file
78
README.md
Normal file
@ -0,0 +1,78 @@
|
||||
# 心率监测 WebSocket 服务
|
||||
|
||||
这是一个基于ASP.NET Core的WebSocket服务,用于接收心率监测设备的数据并转发给其他连接的客户端。
|
||||
|
||||
## 功能
|
||||
|
||||
- 接收心率数据(包含心率值、时间戳和设备名称)
|
||||
- 验证客户端Token确保安全性
|
||||
- 向其他所有已连接的客户端广播心率数据(不包含Token)
|
||||
|
||||
## 技术栈
|
||||
|
||||
- ASP.NET Core 9.0
|
||||
- WebSockets
|
||||
- System.Text.Json
|
||||
|
||||
## 数据格式
|
||||
|
||||
### 接收的数据格式
|
||||
|
||||
```json
|
||||
{
|
||||
"heartRate": 75,
|
||||
"timestamp": "2023-04-10T15:30:45.123Z",
|
||||
"deviceName": "HeartMonitor-X1",
|
||||
"token": "1sZkzBKD3WpRT0eQ9Vk4"
|
||||
}
|
||||
```
|
||||
|
||||
### 广播的数据格式
|
||||
|
||||
```json
|
||||
{
|
||||
"heartRate": 75,
|
||||
"timestamp": "2023-04-10T15:30:45.123Z",
|
||||
"deviceName": "HeartMonitor-X1"
|
||||
}
|
||||
```
|
||||
|
||||
## 使用方式
|
||||
|
||||
1. 启动服务
|
||||
2. 通过WebSocket连接到 `ws://localhost:5000/ws` 或 `wss://localhost:5001/ws`
|
||||
3. 发送包含有效Token的心率数据JSON
|
||||
4. 接收来自其他客户端的心率数据广播
|
||||
|
||||
## 客户端示例代码
|
||||
|
||||
```javascript
|
||||
// 创建WebSocket连接
|
||||
const socket = new WebSocket('ws://localhost:5000/ws');
|
||||
|
||||
// 连接建立时
|
||||
socket.onopen = function(e) {
|
||||
console.log('连接已建立');
|
||||
|
||||
// 发送心率数据
|
||||
const heartRateData = {
|
||||
heartRate: 75,
|
||||
timestamp: new Date(),
|
||||
deviceName: 'HeartMonitor-X1',
|
||||
token: '1sZkzBKD3WpRT0eQ9Vk4'
|
||||
};
|
||||
|
||||
socket.send(JSON.stringify(heartRateData));
|
||||
};
|
||||
|
||||
// 接收消息
|
||||
socket.onmessage = function(event) {
|
||||
const data = JSON.parse(event.data);
|
||||
console.log('收到心率数据:', data);
|
||||
};
|
||||
|
||||
// 连接关闭
|
||||
socket.onclose = function(event) {
|
||||
console.log('连接已关闭', event);
|
||||
};
|
||||
```
|
||||
84
Services/WebSocketManager.cs
Normal file
84
Services/WebSocketManager.cs
Normal file
@ -0,0 +1,84 @@
|
||||
using System.Collections.Concurrent;
|
||||
using System.Net.WebSockets;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using HikarinHeartRateMonitorService.Models;
|
||||
|
||||
namespace HikarinHeartRateMonitorService.Services
|
||||
{
|
||||
public class WebSocketManager
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, WebSocket> _sockets = new();
|
||||
private readonly string _validToken = "1sZkzBKD3WpRT0eQ9Vk4";
|
||||
|
||||
public void AddSocket(string id, WebSocket socket)
|
||||
{
|
||||
_sockets.TryAdd(id, socket);
|
||||
}
|
||||
|
||||
public async Task RemoveSocket(string id)
|
||||
{
|
||||
if (_sockets.TryRemove(id, out var socket))
|
||||
{
|
||||
await socket.CloseAsync(WebSocketCloseStatus.NormalClosure,
|
||||
"Connection closed by the server", CancellationToken.None);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task HandleMessageAsync(string senderId, string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var heartRateData = JsonSerializer.Deserialize<HeartRateData>(message);
|
||||
|
||||
// 验证Token
|
||||
if (heartRateData?.Token != _validToken)
|
||||
{
|
||||
await CloseInvalidConnection(senderId, "Invalid token");
|
||||
return;
|
||||
}
|
||||
|
||||
// 创建不包含Token的响应对象
|
||||
var response = new HeartRateResponse
|
||||
{
|
||||
HeartRate = heartRateData.HeartRate,
|
||||
Timestamp = heartRateData.Timestamp,
|
||||
DeviceName = heartRateData.DeviceName
|
||||
};
|
||||
|
||||
var responseJson = JsonSerializer.Serialize(response);
|
||||
var responseBytes = Encoding.UTF8.GetBytes(responseJson);
|
||||
|
||||
// 向除了发送者之外的所有客户端广播消息
|
||||
var tasks = _sockets
|
||||
.Where(kvp => kvp.Key != senderId)
|
||||
.Select(kvp => SendMessageAsync(kvp.Value, responseBytes));
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
await CloseInvalidConnection(senderId, "Invalid message format");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CloseInvalidConnection(string id, string reason)
|
||||
{
|
||||
if (_sockets.TryGetValue(id, out var socket))
|
||||
{
|
||||
await socket.CloseAsync(WebSocketCloseStatus.InvalidMessageType,
|
||||
reason, CancellationToken.None);
|
||||
await RemoveSocket(id);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task SendMessageAsync(WebSocket socket, byte[] message)
|
||||
{
|
||||
if (socket.State == WebSocketState.Open)
|
||||
{
|
||||
await socket.SendAsync(new ArraySegment<byte>(message),
|
||||
WebSocketMessageType.Text, true, CancellationToken.None);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
8
appsettings.Development.json
Normal file
8
appsettings.Development.json
Normal file
@ -0,0 +1,8 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
}
|
||||
}
|
||||
9
appsettings.json
Normal file
9
appsettings.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"Logging": {
|
||||
"LogLevel": {
|
||||
"Default": "Information",
|
||||
"Microsoft.AspNetCore": "Warning"
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*"
|
||||
}
|
||||
226
wwwroot/index.html
Normal file
226
wwwroot/index.html
Normal file
@ -0,0 +1,226 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="zh">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>心率监测WebSocket测试</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Arial', sans-serif;
|
||||
margin: 0;
|
||||
padding: 20px;
|
||||
background-color: #f5f5f5;
|
||||
color: #333;
|
||||
}
|
||||
.container {
|
||||
max-width: 800px;
|
||||
margin: 0 auto;
|
||||
background-color: white;
|
||||
padding: 20px;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
}
|
||||
h1 {
|
||||
color: #2c3e50;
|
||||
border-bottom: 2px solid #3498db;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
.card {
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 5px;
|
||||
padding: 15px;
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
.card-header {
|
||||
font-weight: bold;
|
||||
margin-bottom: 10px;
|
||||
color: #3498db;
|
||||
}
|
||||
button {
|
||||
background-color: #3498db;
|
||||
color: white;
|
||||
border: none;
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
cursor: pointer;
|
||||
font-size: 14px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
button:hover {
|
||||
background-color: #2980b9;
|
||||
}
|
||||
button:disabled {
|
||||
background-color: #95a5a6;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
input {
|
||||
padding: 8px;
|
||||
border: 1px solid #ddd;
|
||||
border-radius: 4px;
|
||||
width: 60px;
|
||||
}
|
||||
#logs {
|
||||
margin-top: 20px;
|
||||
height: 300px;
|
||||
overflow-y: auto;
|
||||
border: 1px solid #ddd;
|
||||
padding: 10px;
|
||||
background-color: #f9f9f9;
|
||||
font-family: monospace;
|
||||
}
|
||||
.log-entry {
|
||||
margin-bottom: 5px;
|
||||
border-left: 3px solid #3498db;
|
||||
padding-left: 10px;
|
||||
}
|
||||
.received {
|
||||
border-left-color: #2ecc71;
|
||||
}
|
||||
.error {
|
||||
border-left-color: #e74c3c;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>心率监测WebSocket测试</h1>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">连接控制</div>
|
||||
<button id="connectBtn">连接WebSocket</button>
|
||||
<button id="disconnectBtn" disabled>断开连接</button>
|
||||
<span id="connectionStatus">未连接</span>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">发送心率数据</div>
|
||||
<div>
|
||||
<label for="heartRate">心率值:</label>
|
||||
<input type="number" id="heartRate" value="75" min="0" max="250">
|
||||
</div>
|
||||
<div style="margin-top: 10px;">
|
||||
<label for="deviceName">设备名称:</label>
|
||||
<input type="text" id="deviceName" value="HeartMonitor-X1" style="width: 150px;">
|
||||
</div>
|
||||
<div style="margin-top: 10px;">
|
||||
<label for="token">Token:</label>
|
||||
<input type="text" id="token" value="1sZkzBKD3WpRT0eQ9Vk4" style="width: 200px;">
|
||||
</div>
|
||||
<button id="sendBtn" style="margin-top: 10px;" disabled>发送数据</button>
|
||||
</div>
|
||||
|
||||
<div class="card">
|
||||
<div class="card-header">日志</div>
|
||||
<div id="logs"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
let socket = null;
|
||||
const connectBtn = document.getElementById('connectBtn');
|
||||
const disconnectBtn = document.getElementById('disconnectBtn');
|
||||
const sendBtn = document.getElementById('sendBtn');
|
||||
const heartRateInput = document.getElementById('heartRate');
|
||||
const deviceNameInput = document.getElementById('deviceName');
|
||||
const tokenInput = document.getElementById('token');
|
||||
const connectionStatus = document.getElementById('connectionStatus');
|
||||
const logsContainer = document.getElementById('logs');
|
||||
|
||||
function addLogEntry(message, type = 'info') {
|
||||
const entry = document.createElement('div');
|
||||
entry.className = `log-entry ${type}`;
|
||||
entry.textContent = `[${new Date().toLocaleTimeString()}] ${message}`;
|
||||
logsContainer.appendChild(entry);
|
||||
logsContainer.scrollTop = logsContainer.scrollHeight;
|
||||
}
|
||||
|
||||
connectBtn.addEventListener('click', () => {
|
||||
// 判断是HTTP还是HTTPS来决定WebSocket协议
|
||||
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
|
||||
const host = window.location.host;
|
||||
const wsUrl = `${protocol}//${host}/ws`;
|
||||
|
||||
try {
|
||||
socket = new WebSocket(wsUrl);
|
||||
|
||||
socket.onopen = () => {
|
||||
addLogEntry('WebSocket连接已建立');
|
||||
connectBtn.disabled = true;
|
||||
disconnectBtn.disabled = false;
|
||||
sendBtn.disabled = false;
|
||||
connectionStatus.textContent = '已连接';
|
||||
};
|
||||
|
||||
socket.onmessage = (event) => {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
addLogEntry(`收到心率数据: ${JSON.stringify(data, null, 2)}`, 'received');
|
||||
} catch (e) {
|
||||
addLogEntry(`收到非JSON消息: ${event.data}`, 'error');
|
||||
}
|
||||
};
|
||||
|
||||
socket.onclose = (event) => {
|
||||
addLogEntry(`WebSocket连接已关闭: 代码 ${event.code}, 原因: ${event.reason || '未指定'}`);
|
||||
connectBtn.disabled = false;
|
||||
disconnectBtn.disabled = true;
|
||||
sendBtn.disabled = true;
|
||||
connectionStatus.textContent = '未连接';
|
||||
};
|
||||
|
||||
socket.onerror = (error) => {
|
||||
addLogEntry(`WebSocket错误: ${error}`, 'error');
|
||||
};
|
||||
} catch (error) {
|
||||
addLogEntry(`创建WebSocket连接时出错: ${error.message}`, 'error');
|
||||
}
|
||||
});
|
||||
|
||||
disconnectBtn.addEventListener('click', () => {
|
||||
if (socket && socket.readyState === WebSocket.OPEN) {
|
||||
socket.close();
|
||||
addLogEntry('正在关闭WebSocket连接...');
|
||||
}
|
||||
});
|
||||
|
||||
sendBtn.addEventListener('click', () => {
|
||||
if (!socket || socket.readyState !== WebSocket.OPEN) {
|
||||
addLogEntry('WebSocket未连接,无法发送数据', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const heartRate = parseInt(heartRateInput.value);
|
||||
if (isNaN(heartRate) || heartRate < 0 || heartRate > 250) {
|
||||
addLogEntry('心率值无效,请输入0-250之间的数字', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const deviceName = deviceNameInput.value.trim();
|
||||
if (!deviceName) {
|
||||
addLogEntry('设备名称不能为空', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const token = tokenInput.value.trim();
|
||||
if (!token) {
|
||||
addLogEntry('Token不能为空', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
heartRate: heartRate,
|
||||
timestamp: new Date(),
|
||||
deviceName: deviceName,
|
||||
token: token
|
||||
};
|
||||
|
||||
socket.send(JSON.stringify(data));
|
||||
addLogEntry(`已发送心率数据: ${JSON.stringify(data, null, 2)}`);
|
||||
} catch (error) {
|
||||
addLogEntry(`发送数据时出错: ${error.message}`, 'error');
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user