#定義WebSocket對(duì)象(基于線程對(duì)象)
class WebSocket(threading.Thread):
def __init__(self,conn,index,name,remote, path=""):
#初始化線程
threading.Thread.__init__(self)
#初始化數(shù)據(jù),全部存儲(chǔ)到自己的數(shù)據(jù)結(jié)構(gòu)中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) # 返回的是一個(gè)bytes對(duì)象
return WebSocketToken.decode('utf-8')
#運(yùn)行線程
def run(self):
#Log輸出,套接字index啟動(dòng)
if PRINT_FLAG:
print('Socket %s Start!' % self.index)
global g_code_length
global g_header_length
self.handshaken = False #Socket是否握手的標(biāo)志,初始化為false
while True:
if self.handshaken == False: #如果沒有進(jìn)行握手
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會(huì)話收到的只能是utf-8編碼的信息,將接收到的bytes數(shù)據(jù),通過utf-8編碼方式解碼為unicode編碼進(jìn)行處理
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) #按照這種標(biāo)志分割一次,結(jié)果為:header data
#對(duì)header進(jìn)行分割后,取出后面的n-1個(gè)部分
for line in header.split("\r\n")[1:]: #再對(duì)header 和 data部分進(jìn)行單獨(dú)的解析
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))
#握手過程,服務(wù)器構(gòu)建握手的信息,進(jìn)行驗(yàn)證和匹配
#Upgrade: WebSocket 表示為一個(gè)特殊的http請(qǐng)求,請(qǐng)求目的為從http協(xié)議升級(jí)到websocket協(xié)議
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類型進(jìn)行發(fā)送
# 此處需要增加代碼判斷是否成功建立連接
self.handshaken = True #socket連接成功建立之后修改握手標(biāo)志
#向全部連接客戶端集合發(fā)送消息,(環(huán)境套接字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字節(jié)數(shù)據(jù),需要判斷是否接收完所有數(shù)據(jù),如沒有接收完,需要循環(huán)接收完再處理
mm = self.conn.recv(128)
#計(jì)算接受的長度,判斷是否接收完,如未接受完需要繼續(xù)接收
if g_code_length == 0:
get_datalength(mm) # 調(diào)用此函數(shù)可以計(jì)算并修改全局變量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: 數(shù)據(jù)未接收完,接續(xù)接受")
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""
說明
- 本例中對(duì)用戶請(qǐng)求的響應(yīng)均通過此類實(shí)現(xiàn),此類為threading.Thread的子類,我們重寫了run方法,當(dāng)調(diào)用實(shí)例的start方法時(shí),將會(huì)在另外的線程中調(diào)用run方法,實(shí)現(xiàn)多線程。
- run方法分成兩部分來理解,分別為沒有建立socket會(huì)話和建立socket會(huì)話。
- 當(dāng)沒有建立socket會(huì)話時(shí),服務(wù)端接受數(shù)據(jù)進(jìn)行驗(yàn)證和匹配,并發(fā)送歡迎信息,此處需要考慮接受到的數(shù)據(jù)不符合要求時(shí)的動(dòng)作。
- 當(dāng)建立socket會(huì)話后,服務(wù)端接受數(shù)據(jù)并進(jìn)行廣播,此處需要考慮用戶提交的數(shù)據(jù)是否接受完畢的問題。
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。