Python 3.5.2實(shí)現(xiàn)websocket服務(wù)端(五): WebSocket類實(shí)現(xiàn)

#定義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""

說明

  1. 本例中對(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)多線程。
  2. run方法分成兩部分來理解,分別為沒有建立socket會(huì)話和建立socket會(huì)話。
  3. 當(dāng)沒有建立socket會(huì)話時(shí),服務(wù)端接受數(shù)據(jù)進(jìn)行驗(yàn)證和匹配,并發(fā)送歡迎信息,此處需要考慮接受到的數(shù)據(jù)不符合要求時(shí)的動(dòng)作。
  4. 當(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ù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容