❶ 如何用python獲取websocket數據
這里,介紹如何使用 Python 與前端 js 進行通信。
websocket 使用 HTTP 協議完成握手之後,不通過 HTTP 直接進行 websocket 通信。
於是,使用 websocket 大致兩個步驟:使用 HTTP 握手,通信。
js 處理 websocket 要使用 ws 模塊; python 處理則使用 socket 模塊建立 TCP 連接即可,比一般的 socket ,只多一個握手以及數據處理的步驟。
握手
過程
包格式
js 客戶端先向伺服器端 python 發送握手包,格式如下:
?
1
2
3
4
5
6
7
8
GET
/chat HTTP/1.1
Host:
server.example.com
Upgrade:
websocket
Connection:
Upgrade
Sec-WebSocket-Key:
dGhlIHNhbXBsZSBub25jZQ==
Origin:
Sec-WebSocket-Protocol:
chat, superchat
Sec-WebSocket-Version:
13
伺服器回應包格式:
?
1
2
3
4
5
HTTP/1.1
101 Switching Protocols
Upgrade:
websocket
Connection:
Upgrade
Sec-WebSocket-Accept:
s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
Sec-WebSocket-Protocol:
chat
其中, Sec-WebSocket-Key 是隨機的,伺服器用這些數據構造一個 SHA-1 信息摘要。
方法為: key+migic , SHA-1 加密, base-64 加密,如下:
Python 中的處理代碼
?
1
2
MAGIC_STRING='258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
res_key=base64.b64encode(hashlib.sha1(sec_key
+MAGIC_STRING).digest())
握手完整代碼
js 端
js 中有處理 websocket 的類,初始化後自動發送握手包,如下:
var socket = new WebSocket('ws://localhost:3368');
Python 端
Python 用 socket 接受得到握手字元串,處理後發送
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
HOST='localhost'
PORT=3368
MAGIC_STRING='258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
HANDSHAKE_STRING="HTTP/1.1
101 Switching Protocols\r\n"
\
"Upgrade:websocket\r\n"\
"Connection:
Upgrade\r\n"
\
"Sec-WebSocket-Accept:
{1}\r\n"
\
"WebSocket-Location:ws://{2}/chat\r\n"
\
"WebSocket-Protocol:chat\r\n\r\n"
defhandshake(con):
#con為用socket,accept()得到的socket
headers={}
shake=con.recv(1024)
ifnot
len(shake):
returnFalse
header,
data =shake.split('\r\n\r\n',1)
forline
inheader.split('\r\n')[1:]:
key,
val =line.split(':
',1)
headers[key]=val
if'Sec-WebSocket-Key'
not
in
headers:
print('This
socket is not websocket, client close.')
con.close()
returnFalse
sec_key=headers['Sec-WebSocket-Key']
res_key=base64.b64encode(hashlib.sha1(sec_key
+MAGIC_STRING).digest())
str_handshake=HANDSHAKE_STRING.replace('{1}',
res_key).replace('{2}',
HOST +':'
+
str(PORT))
printstr_handshake
con.send(str_handshake)
returnTrue
通信
不同版本的瀏覽器定義的數據幀格式不同, Python 發送和接收時都要處理得到符合格式的數據包,才能通信。
Python 接收
Python 接收到瀏覽器發來的數據,要解析後才能得到其中的有用數據。
瀏覽器包格式
固定位元組:
( 1000 0001 或是 1000 0002 )這里沒用,忽略
包長度位元組:
第一位肯定是 1 ,忽略。剩下 7 個位可以得到一個整數 (0 ~ 127) ,其中
( 1-125 )表此位元組為長度位元組,大小即為長度;
(126)表接下來的兩個位元組才是長度;
(127)表接下來的八個位元組才是長度;
用這種變長的方式表示數據長度,節省數據位。
mark 掩碼:
mark 掩碼為包長之後的 4 個位元組,之後的兄弟數據要與 mark 掩碼做運算才能得到真實的數據。
兄弟數據:
得到真實數據的方法:將兄弟數據的每一位 x ,和掩碼的第 i%4 位做 xor 運算,其中 i 是 x 在兄弟數據中的索引。
完整代碼
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
defrecv_data(self,
num):
try:
all_data=self.con.recv(num)
ifnot
len(all_data):
returnFalse
except:
returnFalse
else:
code_len=ord(all_data[1])
& 127
ifcode_len
==126:
masks=all_data[4:8]
data=all_data[8:]
elifcode_len
==127:
masks=all_data[10:14]
data=all_data[14:]
else:
masks=all_data[2:6]
data=all_data[6:]
raw_str=""
i=0
ford
indata:
raw_str+=chr(ord(d)
^ ord(masks[i%4]))
i+=1
returnraw_str
js 端的 ws 對象,通過 ws.send(str) 即可發送
ws.send(str)
Python 發送
Python 要包數據發送,也需要處理,發送包格式如下
固定位元組:固定的 1000 0001( 『 \x81 ′ )
包長:根據發送數據長度是否超過 125 , 0xFFFF(65535) 來生成 1 個或 3 個或 9 個位元組,來代表數據長度。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
defsend_data(self,
data):
ifdata:
data=str(data)
else:
returnFalse
token="\x81"
length=len(data)
iflength
< 126:
token+=struct.pack("B",
length)
eliflength
<=0xFFFF:
token+=struct.pack("!BH",126,
length)
else:
token+=struct.pack("!BQ",127,
length)
#struct為Python中處理二進制數的模塊,二進制流為C,或網路流的形式。
data='%s%s'
%
(token, data)
self.con.send(data)
returnTrue
js 端通過回調函數 ws.onmessage() 接受數據
?
1
2
3
4
5
ws.onmessage
= function(result,nTime){
alert("從服務端收到的數據:");
alert("最近一次發送數據到現在接收一共使用時間:"+
nTime);
console.log(result);
}
最終代碼
Python服務端
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#
_*_ coding:utf-8 _*_
__author__='Patrick'
importsocket
importthreading
importsys
importos
importMySQLdb
importbase64
importhashlib
importstruct
#
====== config ======
HOST='localhost'
PORT=3368
MAGIC_STRING='258EAFA5-E914-47DA-95CA-C5AB0DC85B11'
HANDSHAKE_STRING="HTTP/1.1
101 Switching Protocols\r\n"
\
"Upgrade:websocket\r\n"\
"Connection:
Upgrade\r\n"
\
"Sec-WebSocket-Accept:
{1}\r\n"
\
"WebSocket-Location:ws://{2}/chat\r\n"
\
"WebSocket-Protocol:chat\r\n\r\n"
classTh(threading.Thread):
def__init__(self,
connection,):
threading.Thread.__init__(self)
self.con=connection
defrun(self):
whileTrue:
try:
pass
self.con.close()
defrecv_data(self,
num):
try:
all_data=self.con.recv(num)
ifnot
len(all_data):
returnFalse
except:
returnFalse
else:
code_len=ord(all_data[1])
& 127
ifcode_len
==126:
masks=all_data[4:8]
data=all_data[8:]
elifcode_len
==127:
masks=all_data[10:14]
data=all_data[14:]
else:
masks=all_data[2:6]
data=all_data[6:]
raw_str=""
i=0
ford
indata:
raw_str+=chr(ord(d)
^ ord(masks[i%4]))
i+=1
returnraw_str
#
send data
defsend_data(self,
data):
ifdata:
data=str(data)
else:
returnFalse
token="\x81"
length=len(data)
iflength
< 126:
token+=struct.pack("B",
length)
eliflength
<=0xFFFF:
token+=struct.pack("!BH",126,
length)
else:
token+=struct.pack("!BQ",127,
length)
#struct為Python中處理二進制數的模塊,二進制流為C,或網路流的形式。
data='%s%s'
%
(token, data)
self.con.send(data)
returnTrue
#
handshake
defhandshake(con):
headers={}
shake=con.recv(1024)
ifnot
len(shake):
returnFalse
header,
data =shake.split('\r\n\r\n',1)
forline
inheader.split('\r\n')[1:]:
key,
val =line.split(':
',1)
headers[key]=val
if'Sec-WebSocket-Key'
not
in
headers:
print('This
socket is not websocket, client close.')
con.close()
returnFalse
sec_key=headers['Sec-WebSocket-Key']
res_key=base64.b64encode(hashlib.sha1(sec_key
+MAGIC_STRING).digest())
str_handshake=HANDSHAKE_STRING.replace('{1}',
res_key).replace('{2}',
HOST +':'
+
str(PORT))
printstr_handshake
con.send(str_handshake)
returnTrue
defnew_service():
"""start
a service socket and listen
when
coms a connection, start a new thread to handle it"""
sock=socket.socket(socket.AF_INET,
socket.SOCK_STREAM)
try:
sock.bind(('localhost',3368))
sock.listen(1000)
#鏈接隊列大小
print"bind
3368,ready to use"
except:
print("Server
is already running,quit")
sys.exit()
whileTrue:
connection,
address =sock.accept()
#返回元組(socket,add),accept調用時會進入waite狀態
print"Got
connection from ",
address
ifhandshake(connection):
print"handshake
success"
try:
t=Th(connection,
layout)
t.start()
print'new
thread for client ...'
except:
print'start
new thread error'
connection.close()
if__name__
=='__main__':
new_service()
js客戶 端
?
1
2
3
4
5
6
7
8
<script>
varsocket
= newWebSocket('ws://localhost:3368');
ws.onmessage
= function(result,nTime){
alert("從服務端收到的數據:");
alert("最近一次發送數據到現在接收一共使用時間:"+
nTime);
console.log(result);
}
</script>
❷ python怎麼連接websocket
websocket是html5引入的一個新特性,傳統的web應用是通過http協議來提供支持,如果要實時同步傳輸數據,需要輪詢,效率低下
websocket是類似socket通信,web端連接伺服器後,握手成功,一直保持連接,可以理解為長連接,這時伺服器就可以主動給客戶端發送數據,實現數據的自動更新。
使用websocket需要注意瀏覽器和當前的版本,不同的瀏覽器提供的支持不一樣,因此設計伺服器的時候,需要考慮。
❸ python怎麼連接websocket
如果只是模擬js端發送接收的話,已經有了websocket server的話,只有client就好了
pip install websocket-client
websocket_client.py(客戶端)
#-*-encoding:utf-8-*-
importsys
sys.path.append("..")
fromsocketimport*
importjson,time,threading
fromwebsocketimportcreate_connection
reload(sys)
sys.setdefaultencoding("utf8")
#config={
#'HOST':'127.0.0.1',
#'PORT':10010
#}
#pipinstallwebsocket-client
classClient():
def__init__(self):
#調用create_connection方法,建立一個websocket鏈接,鏈接是自己的鏈接
self.ws=create_connection("ws://127.0.0.1:10010/xxxx")
#建一個線程,監聽伺服器發送給客戶端的數據
self.trecv=threading.Thread(target=self.recv)
self.trecv.start()
#發送方法,聊天輸入語句時調用,此處默認為群聊ALL
defsend(self,content):
#這里的msg要根據實際需要自己寫
msg={
"type":"POST",
"content":content
}
msg=json.mps(msg)
self.ws.send(msg)
#接收服務端發送給客戶的數據,只要ws處於連接狀態,則一直接收數據
defrecv(self):
try:
whileself.ws.connected:
result=self.ws.recv()
print"receivedmsg:"+str(result)
exceptException,e:
pass
if__name__=='__main__':
c=Client()
#建立鏈接後,就可以按照需要自己send了
c.send(content)
❹ 使用Python Websockets庫建立WebSocket客戶端鏈接
使用with語句進行connect連接後的上下文自動管理,當hello協程退出時,自動關閉該WebSocket連接。
不同於基本示例的是,connect函數中需要指定ssl參數做戚的內容
可以看到與基本示例不同的地方在純森陵於:1.不再使用with進行自動的上下文管理;2.使用while語句進行長連接的處理,如果需要能夠自己控制長連接的關閉,那麼可以設置一個變數比如conn_flag,初始化其值為True,當收到退出連接的命令時,將conn_flag置為False,即可實現連接春運的可控退出。
Enjoy it!