网络套接字意外关闭

websockets closing unexpectedly

4 月 13 日更新: dart 代码始终如一

背景:

我的电视(三星 2019 RU7000)提供了一个安全的 websocket 连接,可以发送 json 数据包来远程控制它。例如

"method":"ms.remote.control", 
"params":{ "Cmd": "Click", "DataOfCmd":"KEY_MUTE" }

可以发送使电视静音。

为了启用访问,已完成握手。客户端连接到 wss://ip:8002/api/v2/samsung.remote.control?name=value,其中 name 的值是 base64 编码的字符串。连接成功后,电视上会弹出window,需要接受。如果用户接受请求,电视将发送包含令牌的 JSON 响应:

"data":{
    "clients":[ ... ],
    "id":"...",
    "token":"28852140"
},
"event":"ms.channel.connect"

此令牌用于通过将 &token=value 附加到 URL 来验证具有相同名称的连接。在用户接受弹出窗口之前发送命令将被忽略。

什么有效

wscatcurl 的命令行方法正在运行。电视显示弹出窗口并发送响应:

$ wscat -n -c https://192.168.0.227:8002/api/v2/channels/samsung.remote.control?name=aW9Ccm9rZXI=
Connected (press CTRL+C to quit)
< {"data":{"clients":[...], "id":"...", "token":"57940060"}, "event":"ms.channel.connect"}

飞镖 - dart.io.WebSocket

以下代码触发弹出窗口并获得响应。

  WebSocket ws = await WebSocket.connect(url,
      compression: CompressionOptions.compressionOff);
  ws.pingInterval = Duration(seconds: 10000);

  ws.listen(print, onError: print, onDone: () {
    print("done");
    print(ws.closeCode);
    print(ws.closeReason);
  });

  await Future.delayed(Duration(seconds: 30));
  ws.close();

问题

我想使用 python 连接到 websocket,验证我的会话并发送远程控制命令。这不适用于以下实现。

python - websocket liris

弹窗没有出现,电视也没有反应。套接字没有关闭。

from websocket import create_connection
from ssl import CERT_NONE 

sock = create_connection(url, sslopt={"cert_reqs": CERT_NONE})

print(sock.recv())

python - websockets aaugustin

弹窗也没有出现,似乎连接被电视关闭了。

from websockets.client import connect, WebSocketClientProtocol
import ssl
import asyncio

async def connect():
    async with connect(url, ssl=ssl.CERT_NONE) as websocket:
        res = await websocket.recv()
        print(res)

asyncio.get_event_loop().run_until_complete(connect())

wireshark log 表明它正在发送 HTTP GET 请求升级 websocket。电视通过关闭与 FIN 和 RST 的连接来响应。


观察

与公开可用的 websocket 服务器的连接与我遇到的问题不同。

许多适用于 python 的流行遥控器都将这两个 websocket 库作为实现的解决方案。 None 其中对我有用。

比较 python 实现和命令行工具发送的数据包对我来说没有明显的区别。

wscat 每四秒向电视发送一个 80 字节长的数据包。我想这是 ping/pong.

我该如何进一步调查?

为什么不使用更高级别的 Python 模块,例如 requests? 您可以尝试以下方法:

import requests

params = (
    ('name', 'aW9Ccm9rZXI='),
)

response = requests.get('https://192.168.0.227:8002/api/v2/channels/samsung.remote.control', params=params)

嗯....我对使用 python websockets 的 websockets 连接有一些经验。 在文章中,您指出您的 websockets 连接将自动与服务器断开连接。

我认为是 websockets 模块中的机制调用 "ping-pong" 导致了这个问题。

机制默认状态为true,这意味着你会定期向websocket服务器发送一个ping信号,如果服务器没有向你发送pong,模块将认为服务器已经shutdown.So你需要做的只是设置 "ping-pong"

status to False.

    async def connect():
    async with connect(url, ssl=ssl.CERT_NONE,close_timeout = None,ping_interval = None) as websocket:
        res = await websocket.recv()
        print(res)

asyncio.get_event_loop().run_until_complete(connect())

以上都是我个人的看法,大家可以试试看

试试 Tornado 的 websocket 实现怎么样?

async def samsung_ws():
    ws_req = HTTPRequest("wss://ip:8002/api/v2/samsung.remote.control?name=value", validate_cert=False)
    ws = await websocket_connect(ws_req)
    ws.write_message("hello")
    while True:
        msg = await ws.read_message()
        if not msg:
            break
        print(msg)

根据网络服务器的构建方式,您可能需要在连接到 websocket 之前请求网页,因为在您的 wscat 示例中我注意到您使用的是 https:// 而不是 wss://.

你能 post 一个飞镖样本 运行(使用了 url)吗?