# WebTCP **Repository Path**: shtml/web-tcp ## Basic Information - **Project Name**: WebTCP - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: main - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-25 - **Last Updated**: 2026-08-26 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # WebTCP Client / Server 一个面向 PLC、DTU、IoT 设备与 Socket 服务的网页版 TCP Client / Server 网络调试工具。浏览器负责交互与编码,Go 后端建立或监听真实 TCP Socket,并通过 WebSocket 双向转发任意二进制数据。 > 安全提示:本服务既能代理 TCP 连接,也能在后端主机上打开 TCP 监听端口。若部署到公网,必须在反向代理或网关层增加身份认证、访问控制、审计与网络隔离,并使用防火墙严格限制端口范围。 ## 架构与数据流 ```text Vue 3 / Element Plus / Pinia │ HTTP + WebSocket (JSON / Base64) ▼ Gin / Gorilla WebSocket │ 每个浏览器一个 WSClient ├── Client: SessionManager ── net.Conn ── PLC / DTU └── Server: ListenerManager ── net.Listener └── accepted session ── TCP Client SQLite: 连接配置、命令模板、应用设置 LocalStorage: 普通发送历史 内存: TX / RX 实时日志(不写数据库) ``` - TCP 层只处理 `[]byte`,不理解 Text 或 HEX。 - 前端将 Text / HEX 编码成 `Uint8Array`,再以 Base64 放入 WebSocket JSON。 - 一个 WebSocket 可管理多个 TCP Session 和 Listener;Server 界面可在多个接入客户端间选择当前回发目标。 - Gorilla WebSocket 由单独 `writeLoop` 串行写入;TCP 同样通过互斥锁串行写入。 - WebSocket 断开会关闭它创建的所有 TCP Session、Listener 和已接入连接,并释放相关 goroutine。 - TCP 是字节流,界面按每次 `conn.Read()` 返回的数据块原样显示,不擅自拆包。 ## 已实现功能 - IPv4、IPv6、域名 TCP Client;连接、断开和连接状态详情 - TCP Server 监听 IPv4 / IPv6 地址;启动、停止、客户端接入与断开状态 - 多客户端收包来源标识,可选择当前客户端回发 Text / HEX 数据 - Text(UTF-8 / ASCII)与 HEX 发送,CR / LF / CRLF,`Ctrl + Enter` - Base64 二进制传输;HEX、Text、HEX + Text 接收显示 - 暂停显示、自动滚动、清空、5000 条上限、TXT 导出 - 循环发送(最小 100 ms),断线自动停止 - TX/RX 包数、字节数、实时速率与连接时长 - LocalStorage 历史去重、计数、收藏、载入、立即发送、单删和清空 - SQLite 连接配置、命令模板与设置 REST API,自动建库与 migration - WebSocket Ping/Pong、资源限制、Context 生命周期和优雅退出 - 解析 DNS 后再校验 IP,默认禁止 loopback、link-local、组播与保留地址 - Docker、Go Embed 单二进制与 Nginx + Go 两种生产部署方式 ## 目录 ```text frontend/ Vue 3 + TypeScript + Vite backend/ cmd/server/ 入口与优雅退出 internal/api/ REST、路由与中间件 internal/database/ SQLite 与 migration internal/security/ 目标地址 / 端口策略 internal/tcp/ TCPSession、SessionManager 与 ListenerManager internal/websocket/ 协议、客户端单写循环与 Hub web/dist/ Go Embed 前端产物 deploy/nginx.conf Dockerfile docker-compose.yml ``` ## 本地开发 要求 Node.js 20.19+(推荐 22)、pnpm 或 npm,以及 Go 1.24+。 后端: ```bash cd backend cp .env.example .env go mod tidy go run ./cmd/server ``` 前端(另一个终端): ```bash cd frontend npm install npm run dev ``` 打开 `http://localhost:5173`。Vite 已将 `/api` 与 `/ws` 代理到 `127.0.0.1:8080`。 ## 配置 复制 `.env.example` 后按环境修改: | 变量 | 默认值 | 说明 | | --- | ---: | --- | | `APP_HOST` / `APP_PORT` | `0.0.0.0` / `8080` | HTTP 监听地址 | | `SQLITE_PATH` | `./data/tcp-client.db` | SQLite 文件 | | `TCP_CONNECT_TIMEOUT` | `5000` | 默认连接超时,毫秒 | | `TCP_IDLE_TIMEOUT` | `1800000` | TCP 空闲超时,毫秒 | | `MAX_TCP_SESSIONS` | `10` | 单浏览器 Session 上限 | | `MAX_TCP_LISTENERS` | `5` | 单浏览器 TCP Listener 上限 | | `MAX_SEND_BYTES` | `1048576` | 单次发送上限 | | `MAX_WS_MESSAGE_BYTES` | `2097152` | WebSocket 消息上限 | | `ALLOW_PRIVATE_IP` | `true` | 是否允许 RFC1918 私网地址 | | `BLOCKED_PORTS` | 空 | 逗号分隔端口黑名单 | | `ALLOWED_ORIGINS` | 本地 Vite | 开发环境 CORS / WS Origin 白名单 | 不论 `ALLOW_PRIVATE_IP` 如何设置,loopback、`0.0.0.0/8`、link-local、组播和保留地址始终禁止。公网部署建议设置类似: ```env ALLOW_PRIVATE_IP=false BLOCKED_PORTS=22,25,3306,5432,6379,2375,2376,9200,27017 ALLOWED_ORIGINS=https://tcp.example.com ``` ## 测试与构建 ```bash cd frontend npm test npm run build cd ../backend go test ./... go vet ./... go build -o tcp-client ./cmd/server ``` ## 生产方式 A:Nginx + Go ```bash cd frontend npm ci npm run build sudo cp -R dist/* /usr/share/nginx/webtcp/ cd ../backend CGO_ENABLED=0 go build -trimpath -o tcp-client ./cmd/server ./tcp-client ``` 将 `deploy/nginx.conf` 放入 Nginx 配置目录并重载。`/api` 与 `/ws` 会代理到 Go `:8080`。 ## 生产方式 B:Go Embed 单二进制 ```bash make embed cd backend ./tcp-client ``` `make embed` 会构建 Vue、复制产物到 `backend/web/dist` 并生成不依赖 CGO 的单一 Go 二进制。运行时只需二进制和可写的 `data/` 目录。 ## Docker ```bash docker compose up -d --build ``` 访问 `http://server:8080`。SQLite 位于命名卷 `webtcp-data` 的 `/app/data/tcp-client.db`,容器重建不会丢失。 注意:容器需要能够路由到被调试设备。跨 VLAN、Docker Desktop 或防火墙环境中,请先确认容器到 PLC / DTU 地址与端口的网络连通性。 TCP Server 的监听发生在容器内。若需要让容器外的设备连接,例如在界面监听 `9000`,还需在 `docker-compose.yml` 的 `ports` 中发布同一端口后重建容器: ```yaml ports: - "8080:8080" - "9000:9000" ``` 非容器部署不需要此映射,但仍需在主机防火墙中允许相应端口。监听 `0.0.0.0` 表示所有 IPv4 网卡,监听 `::` 表示 IPv6。监听器归属当前浏览器 WebSocket,页面关闭或 WebSocket 断开时会自动停止。 ## REST 与 WebSocket REST: ```text GET/POST /api/connection-profiles PUT/DELETE /api/connection-profiles/:id GET/POST /api/command-templates PUT/DELETE /api/command-templates/:id GET/PUT /api/settings GET /healthz ``` WebSocket:`GET /ws`。所有业务消息包含 `type`、`requestId`、`sessionId` 与 `payload`;TCP 字节统一使用 Base64。 - Client:`tcp.connect` / `tcp.connected`、`tcp.disconnect`、`tcp.send`、`tcp.receive`、`tcp.closed` - Server:`tcp.listen` / `tcp.listening`、`tcp.unlisten`、`tcp.accepted`、`tcp.accept_error`、`tcp.server_closed` - Server 接入的客户端也使用普通 Session ID,因此回发仍使用 `tcp.send`;`tcp.receive` 会额外携带 Listener ID 与远端地址。