में वेबस्केट कार्यान्वयन एक पायथन 3 समर्थित अनुप्रयोग के लिए वेब-फ्रंट एंड बनाने की कोशिश कर रहा है। आवेदन को द्वि-दिशात्मक स्ट्रीमिंग की आवश्यकता होगी जो वेबसाइकिलों को देखने के लिए एक अच्छा अवसर की तरह लग रहा है।पायथन 3
मेरा पहला झुकाव पहले से मौजूद कुछ का उपयोग करना था, और mod-pywebsocket से उदाहरण अनुप्रयोगों ने मूल्यवान साबित कर दिया है। दुर्भाग्य से उनका एपीआई आसानी से एक्सटेंशन में उधार नहीं देता है, और यह पायथन 2 है।
ब्लॉगोस्फीयर के चारों ओर देखकर कई लोगों ने वेबसाईट प्रोटोकॉल के पुराने संस्करणों के लिए अपना स्वयं का वेबस्केट सर्वर लिखा है, अधिकांश सुरक्षा कुंजी हैश को लागू नहीं करते हैं, इसलिए काम नहीं करते हैं।
RFC 6455 पढ़ना मैं अपने आप को इस पर एक वार लेने का फैसला किया और के साथ आया था निम्नलिखित:
#!/usr/bin/env python3
"""
A partial implementation of RFC 6455
http://tools.ietf.org/pdf/rfc6455.pdf
Brian Thorne 2012
"""
import socket
import threading
import time
import base64
import hashlib
def calculate_websocket_hash(key):
magic_websocket_string = b"258EAFA5-E914-47DA-95CA-C5AB0DC85B11"
result_string = key + magic_websocket_string
sha1_digest = hashlib.sha1(result_string).digest()
response_data = base64.encodestring(sha1_digest)
response_string = response_data.decode('utf8')
return response_string
def is_bit_set(int_type, offset):
mask = 1 << offset
return not 0 == (int_type & mask)
def set_bit(int_type, offset):
return int_type | (1 << offset)
def bytes_to_int(data):
# note big-endian is the standard network byte order
return int.from_bytes(data, byteorder='big')
def pack(data):
"""pack bytes for sending to client"""
frame_head = bytearray(2)
# set final fragment
frame_head[0] = set_bit(frame_head[0], 7)
# set opcode 1 = text
frame_head[0] = set_bit(frame_head[0], 0)
# payload length
assert len(data) < 126, "haven't implemented that yet"
frame_head[1] = len(data)
# add data
frame = frame_head + data.encode('utf-8')
print(list(hex(b) for b in frame))
return frame
def receive(s):
"""receive data from client"""
# read the first two bytes
frame_head = s.recv(2)
# very first bit indicates if this is the final fragment
print("final fragment: ", is_bit_set(frame_head[0], 7))
# bits 4-7 are the opcode (0x01 -> text)
print("opcode: ", frame_head[0] & 0x0f)
# mask bit, from client will ALWAYS be 1
assert is_bit_set(frame_head[1], 7)
# length of payload
# 7 bits, or 7 bits + 16 bits, or 7 bits + 64 bits
payload_length = frame_head[1] & 0x7F
if payload_length == 126:
raw = s.recv(2)
payload_length = bytes_to_int(raw)
elif payload_length == 127:
raw = s.recv(8)
payload_length = bytes_to_int(raw)
print('Payload is {} bytes'.format(payload_length))
"""masking key
All frames sent from the client to the server are masked by a
32-bit nounce value that is contained within the frame
"""
masking_key = s.recv(4)
print("mask: ", masking_key, bytes_to_int(masking_key))
# finally get the payload data:
masked_data_in = s.recv(payload_length)
data = bytearray(payload_length)
# The ith byte is the XOR of byte i of the data with
# masking_key[i % 4]
for i, b in enumerate(masked_data_in):
data[i] = b^masking_key[i%4]
return data
def handle(s):
client_request = s.recv(4096)
# get to the key
for line in client_request.splitlines():
if b'Sec-WebSocket-Key:' in line:
key = line.split(b': ')[1]
break
response_string = calculate_websocket_hash(key)
header = '''HTTP/1.1 101 Switching Protocols\r
Upgrade: websocket\r
Connection: Upgrade\r
Sec-WebSocket-Accept: {}\r
\r
'''.format(response_string)
s.send(header.encode())
# this works
print(receive(s))
# this doesn't
s.send(pack('Hello'))
s.close()
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.bind(('', 9876))
s.listen(1)
while True:
t,_ = s.accept()
threading.Thread(target=handle, args = (t,)).start()
इस बुनियादी परीक्षण पृष्ठ (जो आधुनिक-pywebsocket साथ काम करता है) का उपयोग करना:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Web Socket Example</title>
<meta charset="UTF-8">
</head>
<body>
<div id="serveroutput"></div>
<form id="form">
<input type="text" value="Hello World!" id="msg" />
<input type="submit" value="Send" onclick="sendMsg()" />
</form>
<script>
var form = document.getElementById('form');
var msg = document.getElementById('msg');
var output = document.getElementById('serveroutput');
var s = new WebSocket("ws://"+window.location.hostname+":9876");
s.onopen = function(e) {
console.log("opened");
out('Connected.');
}
s.onclose = function(e) {
console.log("closed");
out('Connection closed.');
}
s.onmessage = function(e) {
console.log("got: " + e.data);
out(e.data);
}
form.onsubmit = function(e) {
e.preventDefault();
msg.value = '';
window.scrollTop = window.scrollHeight;
}
function sendMsg() {
s.send(msg.value);
}
function out(text) {
var el = document.createElement('p');
el.innerHTML = text;
output.appendChild(el);
}
msg.focus();
</script>
</body>
</html>
यह डेटा प्राप्त करता है और इसे सही तरीके से डेमस्क करता है, लेकिन मुझे काम करने के लिए प्रेषण पथ नहीं मिल सकता है।
एक परीक्षण "हैलो" सॉकेट से लिखने के लिए के रूप में, कार्यक्रम ऊपर की गणना करता है बाइट के रूप में सॉकेट से लिखे जाने की:
['0x81', '0x5', '0x48', '0x65', '0x6c', '0x6c', '0x6f']
कौन सा आरएफसी की section 5.7 में दिए गए स मान से मेल खाते हैं। दुर्भाग्यवश फ्रेम क्रोम के डेवलपर टूल्स में कभी दिखाई नहीं देता है।
कोई विचार जो मुझे याद आ रहा है? या वर्तमान में काम कर रहे Python3 websocket उदाहरण?
टोरनाडो दोनों websockets और पायथन 3 का समर्थन करता है। Http://www.tornadoweb.org/documentation/websocket.html –
धन्यवाद थॉमस। हालांकि मैं पहले एक स्टैंडअलोन कार्यान्वयन करना चाहता हूं - यह मेरे लिए एक समस्या को हल करने के रूप में प्रोटोकॉल को समझने के बारे में बहुत कुछ है। [टर्ननाडो स्रोत कोड] पर एक नज़र डालें (https://github.com/facebook/tornado/blob/master/tornado/websocket.py) मुझे एक हेडर दिखाई देता है ** सेक-वेबस्केट-प्रोटोकॉल ** से भेजा जा रहा है क्लाइंट के लिए सर्वर, लेकिन [spec] (http://tools.ietf.org/html/rfc6455#section-4.2.2) कहता है कि यह वैकल्पिक है। – Hardbyte
यदि कोई ग्राहक उप-प्रोटोकॉल का अनुरोध करता है, तो सर्वर से इसे प्रतिबिंबित करने की उम्मीद है (हमेशा यह मानते हुए कि यह सब-प्रोटोकॉल का समर्थन करता है)। ऐसा करने में विफलता एक हैंडशेक त्रुटि का कारण बनती है, इसलिए यह शायद आपके संदेश भेजने की समस्याओं से संबंधित नहीं है। – simonc