日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > python >内容正文

python

python 3.5.2页面_Python 3.5.2实现websocket服务端

發布時間:2024/7/23 python 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 python 3.5.2页面_Python 3.5.2实现websocket服务端 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

最近由于一個項目需要,寫了一個簡易的websocket服務端程序,其間也參考了網上的很多資料,我將用接下來的幾個篇幅說明是怎么實現的,及遇到的一系列埂。

參考 (包括且不限于如下地址)

涉及到的模塊

socket:socket通訊如偵聽端口接收數據、發送數據等部分需要

struct:對發送和接收的數據包進行解包、打包等

hashlib,base64:通過接收瀏覽器的key生成websocket會話所需要的token

threading:實現多線程

time:對時間的處理

主要涉及到的函數

get_datalength:此函數在建立websocket會話,接受用戶發送的數據后調用,通過解包接收到的bytes信息計算出用戶發送過來的數據總長度及數據幀頭部的大小。websocket幀在封裝不同長度的內容時頭部大小是不一樣的,需要此函數處理后計算出所有數據是否接收完畢。

parser_data:瀏覽器在建立websocket會話后發送過來的bytes數據是有掩碼加密的,此函數在建立websocket會話接受完用戶發送的所有數據后調用,提取出用戶發送過來的實際內容。

sendMessage:在建立websocket會話后,服務端通過socket通道發送數據到瀏覽器端時調用此函數,主要作用是在實際數據包頭部增加websocket數據特有的幀。

定義到的類

WebSocketServer : WebSocket服務器對象,調用此類的begin方法后將開啟服務端程序。

WebSocket:threading.Thread類的子類,處理每一個連接請求。

服務端代碼

# coding: utf-8

import socket

import struct

import hashlib,base64

import threading

import time

connectionlist = {} #存放鏈接客戶fd,元組

g_code_length = 0

g_header_length = 0 #websocket數據頭部長度

PRINT_FLAG = True

"""

經測試發現IE 11瀏覽器在成功建立websocket連接后,會間隔30s發送空信息給服務器以驗證是否處于連接狀態,

因此服務區需要對收到的數據進行解碼并判斷其中載荷內容是否為空,如為空,應不進行廣播

"""

# 計算web端提交的數據長度并返回

def get_datalength(msg):

global g_code_length

global g_header_length

g_code_length = msg[1] & 127

if g_code_length == 126:

g_code_length = struct.unpack('>H', msg[2:4])[0]

g_header_length = 8

elif g_code_length == 127:

g_code_length = struct.unpack('>Q', msg[2:10])[0]

g_header_length = 14

else:

g_header_length = 6

g_code_length = int(g_code_length)

return g_code_length

# 解析web端提交的bytes信息,返回str信息(可以解析中文信息)

def parse_data(msg):

global g_code_length

g_code_length = msg[1] & 127

if g_code_length == 126:

g_code_length = struct.unpack('>H', msg[2:4])[0]

masks = msg[4:8]

data = msg[8:]

elif g_code_length == 127:

g_code_length = struct.unpack('>Q', msg[2:10])[0]

masks = msg[10:14]

data = msg[14:]

else:

masks = msg[2:6]

data = msg[6:]

en_bytes = b""

cn_bytes = []

for i, d in enumerate(data):

nv = chr(d ^ masks[i%4])

nv_bytes = nv.encode()

nv_len = len(nv_bytes)

if nv_len == 1:

en_bytes += nv_bytes

else:

en_bytes += b'%s'

cn_bytes.append(ord(nv_bytes.decode()))

if len(cn_bytes) > 2:

cn_str = ""

clen = len(cn_bytes)

count = int(clen / 3)

for x in range(count):

i = x * 3

b = bytes([cn_bytes[i], cn_bytes[i + 1], cn_bytes[i + 2]])

cn_str += b.decode()

new = en_bytes.replace(b'%s%s%s', b'%s')

new = new.decode()

res = (new % tuple(list(cn_str)))

else:

res = en_bytes.decode()

return res

# 調用socket的send方法發送str信息給web端

def sendMessage(msg):

global connectionlist

send_msg = b"" #使用bytes格式,避免后面拼接的時候出現異常

send_msg += b"\x81"

back_str = []

back_str.append('\x81')

data_length = len(msg.encode()) #可能有中文內容傳入,因此計算長度的時候需要轉為bytes信息

if PRINT_FLAG:

print("INFO: send message is %s and len is %d" % (msg, len(msg.encode('utf-8'))))

# 數據長度的三種情況

if data_length <= 125:#當消息內容長度小于等于125時,數據幀的第二個字節0xxxxxxx 低7位直接標示消息內容的長度

send_msg += str.encode(chr(data_length))

elif data_length <= 65535:#當消息內容長度需要兩個字節來表示時,此字節低7位取值為126,由后兩個字節標示信息內容的長度

send_msg += struct.pack('b', 126)

send_msg += struct.pack('>h', data_length)

elif data_length <= (2^64-1):#當消息內容長度需要把個字節來表示時,此字節低7位取值為127,由后8個字節標示信息內容的長度

send_msg += struct.pack('b', 127)

send_msg += struct.pack('>q', data_length)

else:

print (u'太長了')

send_message = send_msg + msg.encode('utf-8')

for connection in connectionlist.values():

if send_message != None and len(send_message) > 0:

connection.send(send_message)

#刪除連接,從集合中刪除連接對象item

def deleteconnection(item):

global connectionlist

del connectionlist['connection'+item]

#定義WebSocket對象(基于線程對象)

class WebSocket(threading.Thread):

def __init__(self,conn,index,name,remote, path=""):

#初始化線程

threading.Thread.__init__(self)

#初始化數據,全部存儲到自己的數據結構中self

self.conn = conn

self.index = index

self.name = name

self.remote = remote

self.path = path

self.GUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

self.buffer = ""

self.buffer_utf8 = b""

self.length_buffer = 0

def generate_token(self, WebSocketKey):

WebSocketKey = WebSocketKey + self.GUID

Ser_WebSocketKey = hashlib.sha1(WebSocketKey.encode(encoding='utf-8')).digest()

WebSocketToken = base64.b64encode(Ser_WebSocketKey) # 返回的是一個bytes對象

return WebSocketToken.decode('utf-8')

#運行線程

def run(self):

#Log輸出,套接字index啟動

if PRINT_FLAG:

print('Socket %s Start!' % self.index)

global g_code_length

global g_header_length

self.handshaken = False #Socket是否握手的標志,初始化為false

while True:

if self.handshaken == False: #如果沒有進行握手

if PRINT_FLAG:

print('INFO: Socket %s Start Handshaken with %s!' % (self.index,self.remote))

self.buffer = self.conn.recv(1024).decode('utf-8') #socket會話收到的只能是utf-8編碼的信息,將接收到的bytes數據,通過utf-8編碼方式解碼為unicode編碼進行處理

if PRINT_FLAG:

print("INFO: Socket %s self.buffer is {%s}" % (self.index, self.buffer))

if self.buffer.find('\r\n\r\n') != -1:

headers = {}

header, data = self.buffer.split('\r\n\r\n', 1) #按照這種標志分割一次,結果為:header data

#對header進行分割后,取出后面的n-1個部分

for line in header.split("\r\n")[1:]: #再對header 和 data部分進行單獨的解析

key, value = line.split(": ", 1) #逐行的解析Request Header信息(Key,Value)

headers[key] = value

try:

WebSocketKey = headers["Sec-WebSocket-Key"]

except KeyError:

print("Socket %s Handshaken Failed!" % (self.index))

deleteconnection(str(self.index))

self.conn.close()

break

WebSocketToken = self.generate_token(WebSocketKey)

headers["Location"] = ("ws://%s%s" %(headers["Host"], self.path))

#握手過程,服務器構建握手的信息,進行驗證和匹配

#Upgrade: WebSocket 表示為一個特殊的http請求,請求目的為從http協議升級到websocket協議

handshake = "HTTP/1.1 101 Switching Protocols\r\n"\

"Connection: Upgrade\r\n"\

"Sec-WebSocket-Accept: " + WebSocketToken + "\r\n"\

"Upgrade: websocket\r\n\r\n"

self.conn.send(handshake.encode(encoding='utf-8')) # 前文以bytes類型接收,此處以bytes類型進行發送

# 此處需要增加代碼判斷是否成功建立連接

self.handshaken = True #socket連接成功建立之后修改握手標志

#向全部連接客戶端集合發送消息,(環境套接字x的到來)

sendMessage("Welocomg " + self.name + " !")

g_code_length = 0

else:

print("Socket %s Error2!" % (self.index))

deleteconnection(str(self.index))

self.conn.close()

break

else:

# 每次接收128字節數據,需要判斷是否接收完所有數據,如沒有接收完,需要循環接收完再處理

mm = self.conn.recv(128)

#計算接受的長度,判斷是否接收完,如未接受完需要繼續接收

if g_code_length == 0:

get_datalength(mm) # 調用此函數可以計算并修改全局變量g_code_length和g_header_length的值

self.length_buffer += len(mm)

self.buffer_utf8 += mm

if self.length_buffer - g_header_length < g_code_length:

if PRINT_FLAG:

print("INFO: 數據未接收完,接續接受")

continue

else:

if PRINT_FLAG:

print("g_code_length:", g_code_length)

print("INFO Line 204: Recv信息 %s,長度為 %d:" % (self.buffer_utf8, len(self.buffer_utf8)))

if not self.buffer_utf8:

continue

recv_message = parse_data(self.buffer_utf8)

if recv_message == "quit":

print("Socket %s Logout!" % (self.index))

nowTime = time.strftime('%H:%M:%S',time.localtime(time.time()))

sendMessage("%s %s say: %s" % (nowTime, self.remote, self.name+" Logout"))

deleteconnection(str(self.index))

self.conn.close()

break

else:

nowTime = time.strftime('%H:%M:%S',time.localtime(time.time()))

sendMessage("%s %s say: %s" % (nowTime, self.remote, recv_message))

g_code_length = 0

self.length_buffer = 0

self.buffer_utf8 = b""

#WebSocket服務器對象()

class WebSocketServer(object):

def __init__(self):

self.socket = None

self.i = 0

#開啟操作

def begin(self):

if PRINT_FLAG:

print('WebSocketServer Start!')

self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

ip = '10.1.80.83'

port = 8080

if PRINT_FLAG:

print("WebServer is listening %s,%d" % (ip,port))

self.socket.bind((ip,port))

self.socket.listen(50)

#全局連接集合

global connectionlist

while True:

#服務器響應請求,返回連接客戶的信息(連接fd,客戶地址)

connection, address = self.socket.accept()

#根據連接的客戶信息,創建WebSocket對象(本質為一個線程)

#sockfd,index,用戶名,地址

newSocket = WebSocket(connection,self.i,address[0],address)

#線程啟動

newSocket.start()

#更新連接的集合(hash表的對應關系)-name->sockfd

connectionlist['connection'+str(self.i)]=connection

self.i += 1

if __name__ == "__main__":

server = WebSocketServer()

server.begin()

html頁面代碼

WebSocket

html,body{font:normal 0.9em arial,helvetica;}

#log {width:440px; height:200px; border:1px solid #7F9DB9; overflow:auto;}

#msg {width:440px;}

var socket;

function init(){

var host = "ws://10.1.80.83:8080/";

try{

socket = new WebSocket(host);

socket.onopen = function(msg){

console.log("socket session create sucess!");

log("socket session create sucess!");

};

socket.onmessage = function(msg){

console.log("message Sucess");

//socket.send("Hello");

//log(msg.data);

log(msg.data)

};

socket.onclose = function(msg){ console.log("close Sucess"); log("Connection Lose!"); };

socket.onerror = function(msg){ console.log("Error!"); };

}catch(ex){

log(ex);

}

$("msg").focus();

}

function send(){

var txt,msg;

txt = $("msg");

msg = txt.value;

console.log("message is", msg)

if(!msg){

alert("Message can not be empty");

return;

}

txt.value="";

txt.focus();

try{

//log(msg);

socket.send(msg);

}catch(ex){

log(ex);

}

}

window.οnbefοreunlοad=function(){

try{

socket.send('quit');

socket.close();

socket=null;

}catch(ex){

log(ex);

}

};

function $(id){

return document.getElementById(id);

}

function log(msg){

$("log").innerHTML+="
"+msg;

}

function onkey(event){

if(event.keyCode==13){

send();

}

}

WebSocket

發送

總結

以上是生活随笔為你收集整理的python 3.5.2页面_Python 3.5.2实现websocket服务端的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。