2017-05-02 18 views
5

पर वेबसॉकेट संदेश भेजना/प्राप्त करना मैंने एक सरल वेबसाकेट क्लाइंट लिखा था। मैंने SO पर पाया कोड का उपयोग किया, यहां: How can I send and receive WebSocket messages on the server side?पायथन सॉकेट/वेबसॉकेट क्लाइंट

मैं Python 2.7 का उपयोग कर रहा हूं और मेरा सर्वर echo.websocket.org80 टीसीपी पोर्ट पर है। असल में, मुझे लगता है कि मुझे संदेश प्राप्त करने में कोई समस्या है। (या हो सकता है भेजने के भी गलत क्या है?)

कम से कम मैं के बाद से मैं एक अच्छा हाथ मिलाना प्रतिक्रिया प्राप्त करते हैं, यह सुनिश्चित करें कि हाथ मिलाना सब ठीक है हूँ:

HTTP/1.1 101 Web Socket Protocol Handshake 
Access-Control-Allow-Credentials: true 
Access-Control-Allow-Headers: content-type 
Access-Control-Allow-Headers: authorization 
Access-Control-Allow-Headers: x-websocket-extensions 
Access-Control-Allow-Headers: x-websocket-version 
Access-Control-Allow-Headers: x-websocket-protocol 
Access-Control-Allow-Origin: http://example.com 
Connection: Upgrade 
Date: Tue, 02 May 2017 21:54:31 GMT 
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= 
Server: Kaazing Gateway 
Upgrade: websocket 

और मेरे कोड:

#!/usr/bin/env python 
import socket 

def encode_text_msg_websocket(data): 
    bytesFormatted = [] 
    bytesFormatted.append(129) 

    bytesRaw = data.encode() 
    bytesLength = len(bytesRaw) 

    if bytesLength <= 125: 
     bytesFormatted.append(bytesLength) 
    elif 126 <= bytesLength <= 65535: 
     bytesFormatted.append(126) 
     bytesFormatted.append((bytesLength >> 8) & 255) 
     bytesFormatted.append(bytesLength & 255) 
    else: 
     bytesFormatted.append(127) 
     bytesFormatted.append((bytesLength >> 56) & 255) 
     bytesFormatted.append((bytesLength >> 48) & 255) 
     bytesFormatted.append((bytesLength >> 40) & 255) 
     bytesFormatted.append((bytesLength >> 32) & 255) 
     bytesFormatted.append((bytesLength >> 24) & 255) 
     bytesFormatted.append((bytesLength >> 16) & 255) 
     bytesFormatted.append((bytesLength >> 8) & 255) 
     bytesFormatted.append(bytesLength & 255) 

    bytesFormatted = bytes(bytesFormatted) 
    bytesFormatted = bytesFormatted + bytesRaw 
    return bytesFormatted 


def dencode_text_msg_websocket(stringStreamIn): 
    byteArray = [ord(character) for character in stringStreamIn] 
    datalength = byteArray[1] & 127 
    indexFirstMask = 2 
    if datalength == 126: 
     indexFirstMask = 4 
    elif datalength == 127: 
     indexFirstMask = 10 
    masks = [m for m in byteArray[indexFirstMask: indexFirstMask + 4]] 
    indexFirstDataByte = indexFirstMask + 4 
    decodedChars = [] 
    i = indexFirstDataByte 
    j = 0 
    while i < len(byteArray): 
     decodedChars.append(chr(byteArray[i]^masks[j % 4])) 
     i += 1 
     j += 1 
    return ''.join(decodedChars) 

# connect 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.connect((socket.gethostbyname('echo.websocket.org'), 80)) 

# handshake 
handshake = 'GET/HTTP/1.1\r\nHost: echo.websocket.org\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Key: gfhjgfhjfj\r\nOrigin: http://example.com\r\nSec-WebSocket-Protocol: echo\r\n' \ 
     'Sec-WebSocket-Version: 13\r\n\r\n' 
sock.send(handshake) 
print sock.recv(1024) 

# send test msg 
msg = encode_text_msg_websocket('hello world!') 
sock.sendall(msg) 

# receive it back 
response = dencode_text_msg_websocket(sock.recv(1024)) 
print '--%s--' % response 

sock.close() 

यहां क्या गलत है? हैंडशेक के बाद यह जटिल हो जाता है।

dencode_text_msg_websocket विधि एक खाली स्ट्रिंग देता है लेकिन इसे उसी स्ट्रिंग को वापस करना चाहिए जो मैं सर्वर को भेजता हूं, जो hello world! है।

मैं पुस्तकालयों का उपयोग नहीं करना चाहता (मुझे पता है कि उनका उपयोग कैसे करें)। प्रश्न केवल सॉकेट का उपयोग करके, पुस्तकालयों के बिना एक ही चीज़ को प्राप्त करने के बारे में है।

मैं केवल echo.websocket.org server पर एक संदेश भेजना चाहता हूं और एक प्रतिक्रिया प्राप्त कर सकता हूं। मैं हेडर को संशोधित नहीं करना चाहता, बस हेडर का निर्माण करें जैसे कि इस सर्वर द्वारा उपयोग किया जाता है। मैंने जांच की कि वे Wireshark का उपयोग कैसे करना चाहिए, और पाइथन के साथ एक ही पैकेट बनाने की कोशिश की।

नकाबपोश नहीं डेटा सर्वर से ग्राहक के लिए,:

enter image description here

नकाबपोश डेटा, ग्राहक से सर्वर के लिए:

enter image description here

नीचे परीक्षण के लिए, मैं अपने ब्राउज़र का इस्तेमाल किया

+0

आपकी सॉकेट परत स्तर ** उच्च ** है, आप पुनर्गठन के लिए सभी शीर्षकों तक नहीं पहुंच सकते हैं। उपयोग सॉकेट कनेक्शन के लिए तैयार पर केवल टीसीपी या यूडीपी का चयन करें। – dsgdfg

+0

@dsgdfg: मुझे लगता है कि मैं आपको समझ में नहीं आया। मैं केवल 'echo.websocket.org' सर्वर पर एक संदेश भेजना चाहता हूं, बस इतना ही। मैं हेडर को संशोधित नहीं करना चाहता, बस हेडर का निर्माण करें जैसे कि इस सर्वर द्वारा उपयोग किया जाता है। मैंने जांच की कि वे Wireshark का उपयोग कैसे करना चाहिए, और पाइथन के साथ एक ही पैकेट बनाने की कोशिश की। कृपया मेरा संपादन देखें। – yak

+0

डीकोड परिभाषा में आपके कोड और कोड के आधार पर आप एक मूलभूत अंतर है। आप लंबाई को प्राप्त करने के लिए केवल एक वर्ण को परिवर्तित करने पर निर्भर करते हुए इनपुट 'byteArray = stringStreamIn' इनपुट को परिवर्तित नहीं करते हैं। मूल कोड स्ट्रिंगस्ट्रीमइन में वर्ण के लिए संपूर्ण इनपुट स्ट्रिंग 'byteArray = [ord (character) को परिवर्तित करता है] ' –

उत्तर

1

https://tools.ietf.org/html/rfc6455#section-5.1 पर एन्कोडिंग:

आपको क्लाइंट फ्रेम को मास्क करना चाहिए। (और सर्वर फ्रेम बिल्कुल नकाबपोश नहीं है।)

  • एक ग्राहक सभी तख्ते मुखौटा चाहिए यह सर्वर (अधिक जानकारी के लिए धारा 5.3 देखें) को भेजता है। (नोट कि मास्किंग किया जाता है या नहीं, वेबस्केट प्रोटोकॉल टीएलएस पर चल रहा है या नहीं।) सर्वर को फ्रेम प्राप्त करने पर कनेक्शन बंद करना होगा जो मुखौटा नहीं है। इस मामले में, एक सर्वर धारा 7.4.1 में परिभाषित अनुसार 1002 (प्रोटोकॉल त्रुटि) के स्टेटस कोड के साथ बंद फ्रेम भेज सकता है। किसी सर्वर को किसी भी फ्रेम को मास्क नहीं करना चाहिए जो यह क्लाइंट को भेजता है। एक ग्राहक चाहिए एक कनेक्शन बंद करता है, तो यह एक नकाबपोश फ्रेम का पता लगाता है

यह एक काम कर संस्करण है:।

import os 
import array 
import six 
import socket 
import struct 

OPCODE_TEXT = 0x1 

try: 
    # If wsaccel is available we use compiled routines to mask data. 
    from wsaccel.xormask import XorMaskerSimple 

    def _mask(_m, _d): 
     return XorMaskerSimple(_m).process(_d) 

except ImportError: 
    # wsaccel is not available, we rely on python implementations. 
    def _mask(_m, _d): 
     for i in range(len(_d)): 
      _d[i] ^= _m[i % 4] 

     if six.PY3: 
      return _d.tobytes() 
     else: 
      return _d.tostring() 


def get_masked(data): 
    mask_key = os.urandom(4) 
    if data is None: 
     data = "" 

    bin_mask_key = mask_key 
    if isinstance(mask_key, six.text_type): 
     bin_mask_key = six.b(mask_key) 

    if isinstance(data, six.text_type): 
     data = six.b(data) 

    _m = array.array("B", bin_mask_key) 
    _d = array.array("B", data) 
    s = _mask(_m, _d) 

    if isinstance(mask_key, six.text_type): 
     mask_key = mask_key.encode('utf-8') 
    return mask_key + s 


def ws_encode(data="", opcode=OPCODE_TEXT, mask=1): 
    if opcode == OPCODE_TEXT and isinstance(data, six.text_type): 
     data = data.encode('utf-8') 

    length = len(data) 
    fin, rsv1, rsv2, rsv3, opcode = 1, 0, 0, 0, opcode 

    frame_header = chr(fin << 7 | rsv1 << 6 | rsv2 << 5 | rsv3 << 4 | opcode) 

    if length < 0x7e: 
     frame_header += chr(mask << 7 | length) 
     frame_header = six.b(frame_header) 
    elif length < 1 << 16: 
     frame_header += chr(mask << 7 | 0x7e) 
     frame_header = six.b(frame_header) 
     frame_header += struct.pack("!H", length) 
    else: 
     frame_header += chr(mask << 7 | 0x7f) 
     frame_header = six.b(frame_header) 
     frame_header += struct.pack("!Q", length) 

    if not mask: 
     return frame_header + data 
    return frame_header + get_masked(data) 


def ws_decode(data): 
    """ 
    ws frame decode. 
    :param data: 
    :return: 
    """ 
    _data = [ord(character) for character in data] 
    length = _data[1] & 127 
    index = 2 
    if length < 126: 
     index = 2 
    if length == 126: 
     index = 4 
    elif length == 127: 
     index = 10 
    return array.array('B', _data[index:]).tostring() 


# connect 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.connect((socket.gethostbyname('echo.websocket.org'), 80)) 

# handshake 
handshake = 'GET/HTTP/1.1\r\nHost: echo.websocket.org\r\nUpgrade: websocket\r\nConnection: ' \ 
      'Upgrade\r\nSec-WebSocket-Key: gfhjgfhjfj\r\nOrigin: http://example.com\r\nSec-WebSocket-Protocol: ' \ 
      'echo\r\n' \ 
      'Sec-WebSocket-Version: 13\r\n\r\n' 

sock.send(handshake) 
print(sock.recv(1024)) 

sock.sendall(ws_encode(data='Hello, China!', opcode=OPCODE_TEXT)) 

# receive it back 
response = ws_decode(sock.recv(1024)) 
print('--%s--' % response) 

sock.close() 
+0

धन्यवाद। यह अब पूरी तरह से काम करता है। हालांकि, मुझे कुछ कोड भाग नहीं समझा। क्या आप मदद कर सकेंगे? यह: 'frame_header = chr (fin << 7 | rsv1 << 6 | rsv2 << 5 | rsv3 << 4 | opcode) 'और यह:' chr (मुखौटा << 7 | लंबाई) ', आदि। वे क्या करते हैं कर? – yak

+0

@yak https://tools.ietf.org/html/rfc6455#section-5.2 – gushitong

+0

@yak 5.2 देखें। मैंने प्रदान किए गए लिंक में बेस फ़्रेमिंग प्रोटोकॉल –

1

मैं कुछ में अपने कोड हैक कर लिया है कि कम से कम एक उत्तर भेजता है और हेडर को दशमलव के बजाय बाइट स्ट्रिंग डालने के लिए chr() का उपयोग करने के लिए एन्कोडिंग को बदलकर, एक जवाब प्राप्त करता है। डीकोडिंग मैंने अकेला छोड़ा है लेकिन इसके दूसरे जवाब में इसका समाधान है।
इस का असली हिम्मत यहाँ विस्तृत है https://www.rfc-editor.org/rfc/rfc6455.txt
किस विवरण यह वास्तव में क्या आप क्या करना है वह यह है कि

#!/usr/bin/env python 
import socket 
def encode_text_msg_websocket(data): 
    bytesFormatted = [] 
    bytesFormatted.append(chr(129)) 
    bytesRaw = data.encode() 
    bytesLength = len(bytesRaw) 
    if bytesLength <= 125: 
     bytesFormatted.append(chr(bytesLength)) 
    elif 126 <= bytesLength <= 65535: 
     bytesFormatted.append(chr(126)) 
     bytesFormatted.append((chr(bytesLength >> 8)) & 255) 
     bytesFormatted.append(chr(bytesLength) & 255) 
    else: 
     bytesFormatted.append(chr(127)) 
     bytesFormatted.append(chr((bytesLength >> 56)) & 255) 
     bytesFormatted.append(chr((bytesLength >> 48)) & 255) 
     bytesFormatted.append(chr((bytesLength >> 40)) & 255) 
     bytesFormatted.append(chr((bytesLength >> 32)) & 255) 
     bytesFormatted.append(chr((bytesLength >> 24)) & 255) 
     bytesFormatted.append(chr((bytesLength >> 16)) & 255) 
     bytesFormatted.append(chr((bytesLength >> 8)) & 255) 
     bytesFormatted.append(chr(bytesLength) & 255) 
    send_str = "" 
    for i in bytesFormatted: 
     send_str+=i 
    send_str += bytesRaw 
    return send_str 

# connect 
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
sock.settimeout(5.0) 
try: 
    sock.connect((socket.gethostbyname('ws.websocket.org'), 80)) 
except: 
    print "Connection failed" 
handshake = '\ 
GET /echo HTTP/1.1\r\n\ 
Host: echo.websocket.org\r\n\ 
Upgrade: websocket\r\n\ 
Connection: Upgrade\r\n\ 
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==\r\n\ 
Origin: http://example.com\r\n\ 
WebSocket-Protocol: echo\r\n\ 
Sec-WebSocket-Version: 13\r\n\r\n\ 
' 
sock.send(bytes(handshake)) 
data = sock.recv(1024).decode('UTF-8') 
print data 

# send test msg 
msg = encode_text_msg_websocket('Now is the winter of our discontent, made glorious Summer by this son of York') 
print "Sent: ",repr(msg) 
sock.sendall(bytes(msg)) 
# receive it back 
response = sock.recv(1024) 
#decode not sorted so ignore the first 2 bytes 
print "\nReceived: ", response[2:].decode() 
sock.close() 

परिणाम:

HTTP/1.1 101 Web Socket Protocol Handshake 
Access-Control-Allow-Credentials: true 
Access-Control-Allow-Headers: content-type 
Access-Control-Allow-Headers: authorization 
Access-Control-Allow-Headers: x-websocket-extensions 
Access-Control-Allow-Headers: x-websocket-version 
Access-Control-Allow-Headers: x-websocket-protocol 
Access-Control-Allow-Origin: http://example.com 
Connection: Upgrade 
Date: Mon, 08 May 2017 15:08:33 GMT 
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk= 
Server: Kaazing Gateway 
Upgrade: websocket 


Sent: '\x81MNow is the winter of our discontent, made glorious Summer by this son of York' 

Received: Now is the winter of our discontent, made glorious Summer by this son of York 

मैं यहाँ पर ध्यान देना चाहिए, कि यह जा रहा है कुछ अतिरिक्त पुस्तकालयों में खींचने के बिना कोड के लिए एक सुअर बनें, जैसे @ गुशितोंग ने किया है।

संबंधित मुद्दे