ws.receive()
معلق على الرغم من تدفق البيانات من مقبس الويب.
يجب أن ينتج ws.receive
شيئًا ويبلغ عنه.
انها مجرد تعليق / كتل على websocket.
الكود أدناه هو رمز الاتصال.
async def _ws_subscribe(self,
session: ClientSession,
url: str
) -> Dict:
""" Fetch data from web socket asynchronously.
This helper method fetches data from a web socket asynchronously. It is used to
fetch subscribe to websockets of the SkyQ box.
Args:
session (aiohttp.ClientSession): Session to use when fetching the data.
url (str): WebSocket URL to fetch.
Returns:
dict: The body of data returned.
"""
LOGGER.debug(f"Inside _ws_subscribe()...")
async with session.ws_connect(url, autoclose=False) as ws:
while True:
LOGGER.debug(f"Inside _ws_subscribe() infinite loop pre ws.receive.")
payload = await ws.receive()
LOGGER.debug(f"READ SOMETHING! _ws_subscribe() infinite loop post ws.receive")
LOGGER.debug(f'type = {payload.type}')
LOGGER.debug(f'payload data = {payload.data}')
LOGGER.debug(f'payload exception = {ws.exception()}')
if payload.type == aiohttp.WSMsgType.TEXT:
LOGGER.debug('Web-socket data received.')
asyncio.create_task(self._handle(payload))
# asyncio.ensure_future(self._handle(payload))
elif payload.type == aiohttp.WSMsgType.BINARY:
LOGGER.debug('Web-socket binary data received.')
elif payload.type == aiohttp.WSMsgType.PING:
LOGGER.debug('Web-socket ping received')
ws.pong()
elif payload.type == aiohttp.WSMsgType.PONG:
LOGGER.debug('Web-socket pong received')
else:
if payload.type == aiohttp.WSMsgType.CLOSE:
await ws.close()
elif payload.type == aiohttp.WSMsgType.ERROR:
LOGGER.info(f'Error during receive {ws.exception()}')
elif payload.type == aiohttp.WSMsgType.CLOSED:
pass
break
السجل الناتج:
(pyskyq-4vSEKDfZ) ✔ [brad<strong i="6">@bradmac</strong>:~/Code/pyskyq] [16-create-status-end-point-property|✚ 5…2] $ pyskyq -vv green
[2018-09-26 09:12:14] DEBUG:pyskyq.cli:Starting SkyQ...
[2018-09-26 09:12:14] DEBUG:pyskyq.skyremote:Initialised SkyRemote object with host=skyq, port=49160
[2018-09-26 09:12:14] DEBUG:pyskyq.status:Initialised Status object object with host=skyq, port=9006
[2018-09-26 09:12:14] DEBUG:asyncio:Using selector: KqueueSelector
[2018-09-26 09:12:14] DEBUG:pyskyq.status:Asyncio event loop thread running...
[2018-09-26 09:12:14] DEBUG:pyskyq.skyq:Initialised SkyQ object with host=skyq.
[2018-09-26 09:12:14] INFO:pyskyq.cli:Script ends here
[2018-09-26 09:12:14] DEBUG:pyskyq.status:Setting up web socket listener on ws://skyq:9006/as/system/status.
[2018-09-26 09:12:14] DEBUG:pyskyq.status:Inside _ws_subscribe()...
[2018-09-26 09:12:14] DEBUG:asyncio:Get address info skyq:9006, type=<SocketKind.SOCK_STREAM: 1>
[2018-09-26 09:12:14] DEBUG:asyncio:Getting address info skyq:9006, type=<SocketKind.SOCK_STREAM: 1> took 15.352ms: [(<AddressFamily.AF_INET: 2>, <SocketKind.SOCK_STREAM: 1>, 6, '', ('10.0.1.6', 9006))]
[2018-09-26 09:12:14] DEBUG:asyncio:poll 60478.847 ms took 14.299 ms: 1 events
[2018-09-26 09:12:14] DEBUG:asyncio:connect <socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('0.0.0.0', 0)> to ('10.0.1.6', 9006)
[2018-09-26 09:12:14] DEBUG:asyncio:poll 60461.657 ms took 21.045 ms: 1 events
[2018-09-26 09:12:14] DEBUG:asyncio:<socket.socket fd=8, family=AddressFamily.AF_INET, type=SocketKind.SOCK_STREAM, proto=6, laddr=('10.0.1.30', 50141), raddr=('10.0.1.6', 9006)> connected to 10.0.1.6:9006: (<_SelectorSocketTransport fd=8 read=polling write=<idle, bufsize=0>>, <aiohttp.client_proto.ResponseHandler object at 0x1033c8ac8>)
[2018-09-26 09:12:14] DEBUG:asyncio:poll 60429.970 ms took 7.192 ms: 1 events
[2018-09-26 09:12:14] DEBUG:pyskyq.status:Inside _ws_subscribe() infinite loop pre ws.receive.
ومع ذلك ، فإن المقبس مفتوح ويخدم البيانات كما يمكن رؤيتها بواسطة netcat.
(pyskyq-4vSEKDfZ) ✔ [brad<strong i="6">@bradmac</strong>:~/Code/pyskyq] [16-create-status-end-point-property|✚ 5…2] $ nc skyq 9006
GET /as/system/status HTTP/1.1
Host: skyq:9006
Accept: */*
Connection: Upgrade
Upgrade: websocket
�~�{
"camessage" : {
"reason" : "no message",
"state" : "unavailable"
},
"drmstatus" : {
"state" : "available"
},
"entitlements" : [
"ANALYTICS",
"BIGBASIC",
"ETHAN_APP_1",
"HD",
"PDL",
"SKY_DRM_CE",
"SKY_DRM_MR",
"SKY_IPPV",
"ULTRA+",
"SKY+",
"GATEWAYENABLER",
"SIDELOAD"
],
"epginfobits" : {
"epginfobits" : "0xFDE5FFC0",
"mask" : "0x5FFA003F",
"state" : "available"
},
"gatewayservices" : {
"state" : "available"
},
"hdmi" : {
"2160p10bitCapable" : false,
"authenticatedHDCP" : "1.x",
"sinkHDCP" : "1.x",
"sinkHLG" : false,
"sinkUHD" : false,
"state" : "available",
"uhdConfigured" : false
},
"network" : {
"state" : "available"
},
"nssplayback" : {
"state" : "available"
},
"pvr" : {
"state" : "available"
},
"schedule" : {
"lastdate" : "20181003",
"state" : "available"
},
"servicelist" : {
"state" : "available"
},
"smartcard" : {
"active" : true,
"bouquet" : "4101",
"countryCode" : "GBR",
"currency" : "GBP",
"cwe" : true,
"householdid" : "10947783",
"paired" : true,
"state" : "available",
"subbouquet" : "1",
"transactionlimit" : 65535,
"viewingCardNumber" : "725 325 260"
},
"swupdate" : {
"reason" : "IDLE",
"state" : "unavailable"
},
"systemupdates" : {
"entitlements" : 2,
"install" : 1,
"servicegenres" : 1,
"smartcard" : 1
},
"updatetask" : {
"reason" : "no update",
"state" : "unavailable"
}
}
^C(pyskyq-4vSEKDfZ) ✔ [brad<strong i="7">@bradmac</strong>:~/Code/pyskyq] [16-create-status-end-point-property|✚ 5…2] $
(pyskyq-4vSEKDfZ) ✔ [brad<strong i="6">@bradmac</strong>:~/Code/pyskyq] [16-create-status-end-point-property|✚ 5…2] $ uname -a
Darwin bradmac 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64
(pyskyq-4vSEKDfZ) ✔ [brad<strong i="7">@bradmac</strong>:~/Code/pyskyq] [16-create-status-end-point-property|✚ 5…2] $ pip freeze
aiohttp==3.4.4
appnope==0.1.0
arrow==0.12.1
async-timeout==3.0.0
async-upnp-client==0.12.4
attrs==18.2.0
backcall==0.1.0
binaryornot==0.4.4
bleach==2.1.3
certifi==2018.4.16
chardet==3.0.4
click==6.7
cookiecutter==1.6.0
cycler==0.10.0
decorator==4.3.0
Django==2.1.1
entrypoints==0.2.3
ez-setup==0.9
future==0.16.0
html5lib==1.0.1
idna==2.7
idna-ssl==1.1.0
ipykernel==4.8.2
ipython==6.4.0
ipython-genutils==0.2.0
ipywidgets==7.2.1
jedi==0.12.0
Jinja2==2.10
jinja2-time==0.2.0
jsonschema==2.6.0
jupyter==1.0.0
jupyter-client==5.2.3
jupyter-console==5.2.0
jupyter-core==4.4.0
kaggle==1.4.2
kiwisolver==1.0.1
MarkupSafe==1.0
matplotlib==2.2.2
mistune==0.8.3
multidict==4.4.2
nbconvert==5.3.1
nbformat==4.4.0
notebook==5.5.0
numpy==1.14.4
pandocfilters==1.4.2
parso==0.2.1
pexpect==4.6.0
pickleshare==0.7.4
pipenv==2018.7.1
poyo==0.4.1
prompt-toolkit==1.0.15
ptyprocess==0.6.0
Pygments==2.2.0
pyparsing==2.2.0
PyScaffold==3.0.3
python-dateutil==2.7.3
python-didl-lite==1.1.0
pytz==2018.4
pyzmq==17.0.0
qtconsole==4.3.1
requests==2.19.1
Send2Trash==1.5.0
simplegeneric==0.8.1
six==1.11.0
terminado==0.8.1
testpath==0.3.1
tornado==5.0.2
tqdm==4.24.0
traitlets==4.3.2
urllib3==1.22
virtualenv==16.0.0
virtualenv-clone==0.3.0
voluptuous==0.11.5
wcwidth==0.1.7
webencodings==0.5.1
whichcraft==0.4.1
widgetsnbextension==3.2.1
yarl==1.2.6
(pyskyq-4vSEKDfZ) ✔ [brad<strong i="8">@bradmac</strong>:~/Code/pyskyq] [16-create-status-end-point-property|✚ 5…2] $
تحديث...
إصدار Python هو 3.7.0
يعتقد GitMate.io أن https://github.com/aio-libs/aiohttp/issues/2200 (مآخذ ويب العميل الخلفية معلقة على SIGINT) ، https://github.com/aio-libs/aiohttp/issues/ 1002 (استجابة Websocket .close () يمكن أن تتوقف إلى أجل غير مسمى) ، https://github.com/aio-libs/aiohttp/issues/376 (ProactorEventLoop توقف) ، https://github.com/aio-libs/aiohttp/issues / 3027 (تعليق ws_connect) و https://github.com/aio-libs/aiohttp/issues/265 (تنفيذ websocket من جانب العميل).
يبدو أن client_ws.py # L204 لا يعود ... أي أفكار؟
الخادم عبارة عن جهاز فك تشفير SkyQ ، لذلك قد لا يكون تطبيق WS متوافقًا تمامًا مع RFC. على سبيل المثال ، لا يحترم ping / poings ... وهناك ذلك الغريب �~�
في الحمولة ... لست متأكدًا مما إذا كان هذا رمز التشغيل أو بعض المراوغات الأخرى ...
Websocket هو بروتوكول ثنائي �~�
يشفر نوع الرسالة وطولها.
عذرًا ، لا يمكنني مساعدتك بدون مشاركتك في فك تشفيرها ومقارنتها بحجم الحمولة الفعلية.
�~�
هو 001111110111111000111111
في النظام الثنائي ، وهو: 3F7E3F
في النظام الست عشري.
تبدو تلك البايتات مثل هذه النهاية إلى النهاية ...
00111111
01111110
00111111
لست خبيرا في RFC ولكن ما هذا القول من حيث النوع والطول؟
هل تعتقد أن المشكلة في ذلك؟ أي لا توافق على طول الحمولة الفعلي ، والشيء الذي ينتظر إطارًا إضافيًا ، على سبيل المثال؟
ومن المثير للاهتمام ، أن عميل cli لمقبس الويب هذا ، المكتوب في go ، يتعامل مع الإخراج بشكل جيد ، بما في ذلك الأشياء الثنائية في الجزء العلوي:
""
ws ws: // skyq: 9006 / as / system / status
<{
"camessage": {
"السبب": "لا توجد رسالة"،
"الحالة": "غير متوفر"
} ،
"drmstatus": {
"الحالة": "متاح"
} ،
"الاستحقاقات": [
"التحليلات"،
"BIGBASIC"،
"ETHAN_APP_1" ،
"عالية الدقة"،
"PDL" ،
"SKY_DRM_CE" ،
"SKY_DRM_MR" ،
"SKY_IPPV"،
"ULTRA +"،
"سكاى +"،
"GATEWAYENABLER" ،
"سيدلواد"
] ،
"epginfobits": {
"epginfobits": "0xFDE5FFC0"،
"قناع": "0x5FFA003F" ،
"الحالة": "متاح"
} ،
"gatewayservices": {
"الحالة": "متاح"
} ،
"hdmi": {
"2160p10bitCapable": خطأ ،
"مصدق HDCP": "NONE"،
"السبب": "تم تعطيل منفذ إخراج HDMI" ،
"sinkHDCP": "NONE"،
"sinkHLG": خطأ ،
"sinkUHD": خطأ ،
"الحالة": "غير متوفر" ،
"uhdConfigured": خطأ
} ،
"شبكة الاتصال" : {
"الحالة": "متاح"
} ،
"nssplayback": {
"الحالة": "متاح"
} ،
"pvr": {
"الحالة": "متاح"
} ،
"جدول" : {
"lastdate": "20181003"،
"الحالة": "متاح"
} ،
"قائمة الخدمة": {
"الحالة": "متاح"
} ،
"بطاقة ذكية" : {
"نشط": صحيح ،
"باقة": "4101"،
"countryCode": "GBR" ،
"العملة": "جنيه إسترليني"،
"cwe": صحيح ،
"المنزلية": "10947783" ،
"زوجي": صحيح ،
"الحالة": "متاح" ،
"باقة فرعية": "1"،
"حد المعاملة": 65535 ،
"viewCardNumber": "725325260"
} ،
"swupdate": {
"السبب": "IDLE" ،
"الحالة": "غير متوفر"
} ،
"تحديثات النظام" : {
"الاستحقاقات": 2 ،
"تثبيت": 1 ،
"servicegenres": 1 ،
"البطاقة الذكية": 1
} ،
"updatetask": {
"السبب": "لا يوجد تحديث"،
"الحالة": "غير متوفر"
}
}
^ ج
يقطع
✔ [ brad @ bradmac : ~] $ ``
يقول البروتوكول: أول 3F
بايت في رسالة WS ممنوع (محجوز للاستخدام في المستقبل).
هل أنت متأكد أنك لم تفوت شيئًا؟
أفترض أنك تشير إلى البتات 2d و 3 و 4 في بروتوكول التأطير الأساسي. في هذه الحالة ، نعم ، ربما أخطأت في الأمر. يمكن أن تكون مشكلة يونيكود / ASCII. سآخذ نظرة أخرى.
لقد جربت بعض المحولات الأخرى عبر الإنترنت ... أتلقى هذا الآن:
عرافة = ef bf bd 7e ef bf bd
ثنائي = 11101111 10111111 10111101 01111110 11101111 10111111 10111101
إذا كان وفقًا لـ RFC 6455
5.2. Base Framing Protocol
This wire format for the data transfer part is described by the ABNF
[RFC5234] given in detail in this section. (Note that, unlike in
other sections of this document, the ABNF in this section is
operating on groups of bits. The length of each group of bits is
indicated in a comment. When encoded on the wire, the most
significant bit is the leftmost in the ABNF). A high-level overview
of the framing is given in the following figure. In a case of
conflict between the figure below and the ABNF specified later in
this section, the figure is authoritative.
0 1 2 3
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+-+-+-+-+-------+-+-------------+-------------------------------+
|F|R|R|R| opcode|M| Payload len | Extended payload length |
|I|S|S|S| (4) |A| (7) | (16/64) |
|N|V|V|V| |S| | (if payload len==126/127) |
| |1|2|3| |K| | |
+-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - +
| Extended payload length continued, if payload len == 127 |
+ - - - - - - - - - - - - - - - +-------------------------------+
| |Masking-key, if MASK set to 1 |
+-------------------------------+-------------------------------+
| Masking-key (continued) | Payload Data |
+-------------------------------- - - - - - - - - - - - - - - - +
: Payload Data continued ... :
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
| Payload Data continued ... |
+---------------------------------------------------------------+
FIN: 1 bit
Indicates that this is the final fragment in a message. The first
fragment MAY also be the final fragment.
RSV1, RSV2, RSV3: 1 bit each
MUST be 0 unless an extension is negotiated that defines meanings
for non-zero values. If a nonzero value is received and none of
the negotiated extensions defines the meaning of such a nonzero
value, the receiving endpoint MUST _Fail the WebSocket
Connection_.
ثم يبدو أنه يتم تعيين RSV1
و RSV2
على 1 ، كما تقترح ، ما لم يتم التفاوض على بعض etxension؟ ليس لدي فكره.
عدد الأحرف في مستند JSON هو 1703
يقول RFC هذا عن طول الحمولة:
Payload length: 7 bits, 7+16 bits, or 7+64 bits
The length of the "Payload data", in bytes: if 0-125, that is the
payload length. If 126, the following 2 bytes interpreted as a
16-bit unsigned integer are the payload length. If 127, the
following 8 bytes interpreted as a 64-bit unsigned integer (the
most significant bit MUST be 0) are the payload length. Multibyte
length quantities are expressed in network byte order. Note that
in all cases, the minimal number of bytes MUST be used to encode
the length, for example, the length of a 124-byte-long string
can't be encoded as the sequence 126, 0, 124. The payload length
is the length of the "Extension data" + the length of the
"Application data". The length of the "Extension data" may be
zero, in which case the payload length is the length of the
"Application data".
إذن ، بالنظر إلى كل ذلك ، إلى أين نذهب بعد ذلك؟ إذا كان الخادم ميتًا عقليًا وغير متوافق مع RFC ، فأنا بحاجة إلى حله حيث من الواضح أن العميل الآخر يمكنه فعل ذلك ... هل يمكنك تقديم أي اقتراحات؟
لا يزال يبدو مريبًا.
الامتداد الوحيد المعروف هو WebSocket compression الذي يستخدم RSV1. لا أعرف ما هو الامتداد الذي يستخدم RSV2.
علاوة على ذلك ، يتم حجز كود التشغيل FF أيضًا ويجب عدم استخدامه.
ما لم تكن تعرف ما يرسله الخادم ، فلا توجد طريقة "لإصلاح" العميل.
asvetlov لقد جربت مكتبة websockets
وهي تعمل ... لذا سأذهب مع ذلك ، حيث لا يمكنني قضاء المزيد من الوقت في تصحيح أخطاء هذه المكتبة معك ...
aoihttp
- لا يعملimport asyncio
import logging
import sys
import aiohttp
LOGGER = logging.getLogger(__name__)
logformat = "[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout,
format=logformat, datefmt="%Y-%m-%d %H:%M:%S")
async def main():
async with aiohttp.ClientSession() as session:
async with session.ws_connect('http://skyq:9006/as/system/status') as ws:
payload = await ws.receive()
print(payload.text)
loop = asyncio.get_event_loop()
loop.run_until_complete(main())
websockets
- يعملimport asyncio
import websockets
import logging
import sys
LOGGER = logging.getLogger(__name__)
logformat = "[%(asctime)s] %(levelname)s:%(name)s:%(message)s"
logging.basicConfig(level=logging.DEBUG, stream=sys.stdout,
format=logformat, datefmt="%Y-%m-%d %H:%M:%S")
async def hello():
async with websockets.connect(
'ws://skyq:9006/as/system/status') as websocket:
payload = await websocket.recv()
print(f"{payload}")
asyncio.get_event_loop().run_until_complete(hello())
لا توجد رسوم لإغلاق هذه التذكرة إذا كنت ترغب في ذلك ، ولكن قد ترغب في إبقائها مفتوحة حيث يبدو أنها خطأ ... أو على الأقل حالة لا تخضع لقانون Postel.
أنا أقدر مساعدتك في محاولة معالجة هذا.
لا يزال يبدو مريبًا.
الامتداد الوحيد المعروف هو WebSocket compression الذي يستخدم RSV1. لا أعرف ما هو الامتداد الذي يستخدم RSV2.
علاوة على ذلك ، يتم حجز كود التشغيل FF أيضًا ويجب عدم استخدامه.
مرحبا asvetlov
ما لم تكن تعرف ما يرسله الخادم ، فلا توجد طريقة "لإصلاح" العميل.
أعتقد أنك تعني "إلا إذا كنت لا تعرف ما يرسل الخادم، لا يمكنك إصلاح عميل".
في هذه الحالة ، أنا أختلف تمامًا مع هذه النقطة.
هل أنت على دراية بمبدأ المتانة ؟
"كن محافظًا فيما ترسله ، وليبراليًا فيما تتلقى".
بغض النظر عن الضرورات التي يجب أن يتعيّن عليها ويجب عدمه ، في RFC ، أعتقد أنك تفسر وتتوقع من الكيانات الامتثال لـ RFC _ تمامًا _... من الواضح أنها لا تفعل ذلك ، والعديد من خوادم الإنترنت والعملاء هناك ، من مختلف الأنواع ، لديهم تطبيقات نصف مريعة مريعة للبروتوكولات.
يجب أن يكون التنفيذ الجيد للمكتبة / البروتوكول متسامحًا مع هؤلاء إلى الحد الذي يمكنه. انظر RFC1122 . من الممكن تمامًا كتابة عميل بروتوكول ليكون متسامحًا مع (بعض) انتهاكات البروتوكول دون الوصول إلى المشارك الآخر في الاتصال.
أشعر أن هذا ليس هو الحال هنا ، يبدو أنك تتبنى وجهة نظر متشددة مفادها أنه إذا لم يكن المضيف متوافقًا بنسبة 100٪ فهذا سيء جدًا بالنسبة له ، فلن نتحدث معه. هذا سيء للغاية. إنه مثل القول: "أنا أتحدث الإنجليزية للملكة فقط ، وإذا أتيت تتحدث معي بلهجة إنجليزية غريبة ، فلن أتحدث معك."
من الواضح أن هذا ليس نهجًا جيدًا إذا كان الهدف الكامل للمكتبة هو تسهيل الاتصال.
اقتراحي ، لذلك ، هو التفكير في المكان الذي يمكنك فيه تخفيف المتطلبات الصارمة للبروتوكول (ربما عبر طريقة kwargs ، التي تقوم بتشغيل المناولة "المريحة") ، ومعرفة ما إذا كان يمكنك جعل الأشياء تتحدث حتى عندما لا يتصرف الجانب الآخر بشكل صحيح .
بصرف النظر عن هذا النقد ، أود أن أشكرك والمساهمين من aio-libs
على كل عملك من أجل المجتمع. 👍 🥇
asvetlov مجرد تحديث لهذا ... اكتشفت أن الخادم (غير المتوافق) يتطلب رأسًا كبيرًا Upgrade:
قبل أن يعمل. فكرت في أنني سأذكرها في حالة النظر في قضية رؤوس حالة العنوان من قبلكم يا رفاق ... هذه حالة حقيقية لانتهاك بروتوكول من خادم تم تنفيذه بشكل سيئ مما يتسبب في عدم عمل عميل websocket ..