{"record":{"id":"8561a93999faf1d6","repo":"jlcodes99/cockpit-tools","slug":"ws-8561a9","errorCode":null,"errorMessage":"[WS] 接收错误 {}: {}","messagePattern":"\\[WS\\] 接收错误 (.+?): (.+?)","errorType":"console","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/cockpit-core/src/modules/websocket.rs","lineNumber":567,"sourceCode":"    // 订阅广播\n    let mut broadcast_rx = server.tx.subscribe();\n\n    loop {\n        tokio::select! {\n            // 接收客户端消息\n            msg = ws_receiver.next() => {\n                match msg {\n                    Some(Ok(Message::Text(text))) => {\n                        if let Err(e) = handle_client_message(&server, &mut ws_sender, &text).await {\n                            crate::modules::logger::log_error(&format!(\"[WS] 处理消息失败: {}\", e));\n                        }\n                    }\n                    Some(Ok(Message::Close(_))) => {\n                        crate::modules::logger::log_info(&format!(\"[WS] 客户端断开: {}\", addr));\n                        break;\n                    }\n                    Some(Err(e)) => {\n                        crate::modules::logger::log_error(&format!(\"[WS] 接收错误 {}: {}\", addr, e));\n                        break;\n                    }\n                    None => break,\n                    _ => {}\n                }\n            }\n            // 发送广播消息\n            msg = broadcast_rx.recv() => {\n                if let Ok(json) = msg {\n                    if ws_sender.send(Message::Text(json.into())).await.is_err() {\n                        break;\n                    }\n                }\n            }\n        }\n    }\n\n    // 移除客户端","sourceCodeStart":549,"sourceCodeEnd":585,"githubUrl":"https://github.com/jlcodes99/cockpit-tools/blob/1ed8b77992d62ca81fabf744deb0839ad361d5bf/crates/cockpit-core/src/modules/websocket.rs#L549-L585","documentation":"Logged in the receive branch of the per-connection select! loop when ws_receiver.next() yields Some(Err(e)), meaning the underlying tungstenite stream errored while reading. This is a transport/protocol-level failure, not an application error: the loop breaks and the connection is torn down. Typical causes are the peer dropping TCP abruptly, IO errors, or tungstenite protocol violations.","triggerScenarios":"The client process is killed or the socket is reset (Connection reset by peer) mid-session; the TCP connection times out; the peer sends frames violating the WebSocket protocol; the OS reports a broken pipe while reading.","commonSituations":"Laptops sleeping / network switches dropping loopback-unrelated links; client crash or force-quit without a Close frame; aggressive proxies or firewalls idling out the connection; mismatched WS protocol extensions (e.g. permessage-deflate negotiation issues).","solutions":["Treat it as a disconnect: the server already breaks the loop; have the client detect the drop and reconnect with backoff.","Check the logged tungstenite error: 'ConnectionReset'/'BrokenPipe' means abrupt client termination; 'Protocol(…)' means a malformed frame from the client.","Add client-side keepalive/ping to detect dead connections before proxies or timeouts kill them.","If a proxy/firewall idles out the socket, lower the ping interval or bypass the proxy for 127.0.0.1 traffic."],"exampleFix":"// before: no keepalive, connection silently dies behind a proxy\nconst ws = new WebSocket(\"ws://127.0.0.1:9100\");\n// after: ping periodically and reconnect on close\nsetInterval(() => ws.readyState === 1 && ws.ping(), 15000);\nws.onclose = () => setTimeout(connect, 1000);","handlingStrategy":"retry","validationCode":"// client side: check socket state before each use and reconnect on close\nif (ws.readyState !== WebSocket.OPEN) {\n  await reconnectWithBackoff(); // e.g. delay = min(30s, 500ms * 2**attempt)\n}","typeGuard":null,"tryCatchPattern":"match msg {\n    Some(Err(e)) => {\n        log_error(&format!(\"[WS] 接收错误 {}: {}\", addr, e));\n        break; // tear down; client reconnects with backoff\n    }\n    Some(Ok(_)) => { /* handle frame */ }\n    None => break,\n}","preventionTips":["Implement exponential-backoff reconnect on the client.","Send periodic pings so dead connections are detected quickly.","Avoid idle timeouts by keeping traffic flowing or raising proxy/firewall timeouts.","Only send a Close frame and await it during clean shutdowns to reduce reset noise."],"tags":["websocket","network","connection-reset","rust"],"backgroundTag":"websocket-connection-reset","analyzedSha":"1ed8b77992d62ca81fabf744deb0839ad361d5bf","analyzedAt":"2026-09-05T09:51:41.178Z","contentChangedAt":"2026-09-05T09:51:41.178Z","schemaVersion":2},"datasetVersion":"2026-09-12T12:17:11.808Z"}