python websocet回调,通过Python套接字/ WebSocket客户端发送/接收WebSocket消息

I wrote a simple WebSocket client. I used the code I found on SO, here: How can I send and receive WebSocket messages on the server side?.

I'm using Python 2.7 and my server is echo.websocket.org on 80 TCP port. Basically, I think that I have a problem with receiving messages. (Or maybe the sending is wrong too?)

At least I am sure that the handshake is all ok, since I receive a good handshake response:

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

And my code:

#!/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()

What is wrong here? It gets complicated after the handshake.

The dencode_text_msg_websocket method returns an empty string but it should return the same string I send to the server, which is hello world!.

I DO NOT WANT to use libraries (I know how to use them). The question is about achieving the same thing WITHOUT libraries, using only sockets.

I only want to send a message to echo.websocket.org server and receive a response, that's all. I do not want to modify the headers, just build the headers like they're used by this server. I checked how they should look like using Wireshark, and tried to build the same packets with Python.

For tests below, I used my browser:

Not masked data, from server to client:

6vBj2.png

Masked data, from client to server:

JVmVq.png

解决方案

You should mask the client frames. (And the server frames is not masked at all.)

a client MUST mask all frames that it

sends to the server (see Section 5.3 for further details). (Note

that masking is done whether or not the WebSocket Protocol is running

over TLS.) The server MUST close the connection upon receiving a

frame that is not masked. In this case, a server MAY send a Close

frame with a status code of 1002 (protocol error) as defined in

Section 7.4.1. A server MUST NOT mask any frames that it sends to

the client. A client MUST close a connection if it detects a masked

frame。

This is a working version:

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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值