基於Html5 websocket和Python的線上聊天室

來源:互聯網
上載者:User

一、什麼是WebSocket
API

     WebSocket API是下一代用戶端-伺服器的非同步通訊方法。該通訊取代了單個的TCP通訊端,使用ws或wss協議,可用於任意的用戶端和伺服器程式。WebSocket目前由W3C進行標準化。WebSocket已經受到Firefox
4、Chrome 4、Opera 10.70以及Safari 5等瀏覽器的支援。

     WebSocket API最偉大之處在於伺服器和用戶端可以在給定的時間範圍內的任意時刻,相互推送資訊。WebSocket並不限於以Ajax(或XHR)方式通訊,因為Ajax技術需要用戶端發起請求,而WebSocket伺服器和用戶端可以彼此相互推送資訊;XHR受到域的限制,而WebSocket允許跨域通訊。
二、WebSocket協議     websocket的協議是很簡單的,這裡我把它分成用戶端和服務端來講。在用戶端,new WebSocket即可執行個體化一個新的websocket對象,但其參數略微有一點不一樣,參數格式是這樣的ws://yourdomain:port/path
,WebSocket對象會自動解析這段字串,發送到指定伺服器連接埠,首先執行的是雙方握手(handshake),用戶端發送資料格式類似這樣:
GET /chat HTTP/1.1Upgrade: WebSocketConnection: UpgradeHost: www.zendstudio.net:9108Origin: http://www.zendstudio.netCookie: somenterCookie

這很是有些類似於http的頭資訊,同樣每行都是以”\r\n”結尾的,上面這段格式無需我們去構造,WebSocket對象會自動發送,對用戶端這是透明的。此時服務端應該返回的資訊是:

HTTP/1.1 101 Web Socket Protocol HandshakeUpgrade: WebSocketConnection: UpgradeWebSocket-Origin: http://www.zendstudio.netWebSocket-Location: ws://www.zendstudio.net:9108/chat

從這裡我們太容易看出來,websocket協議的握手部分根本就是個類http的協議,所不同的是http每次都會有這樣子的頭資訊互動,這在某些時候不得不顯得很糟糕。而websocket只會執行一次這個過程,之後的傳輸資訊就變得異常簡潔了。

握手協議:request中有三個隨機的key值,頭部有兩個,後面body裡是長度為8位元組的key3(括弧裡的文字是提示,還有字元間的冒號也是為了看上去清晰才加上的,真正傳輸是沒有的),以此向server發送一個challenge,server需要根據這三個key計算出一個token,在響應中發回給client,以證明自己對request的正常解讀。計算方法是這樣的:對於key1,抽取其中的數字字元,形成一個整數num,然後除以他自身的空格數spaces,保留整數部分i1;
key2如法炮製,得到i2,把i1和i2按照big-endian字元序串連起來,然後再與key3串連,得到一個初始的序列,對這個序列使用md5計算出一個16位元組長的摘要,就是所需的token。另外值得注意的是Origin頭部,意味著Websocket是支援cross origin的。

三、用戶端client.html
<html><head><title>WebSocket</title> <style> html,body{font:normal 0.9em arial,helvetica;} #log {width:440px; height:200px; border:1px solid #7F9DB9; overflow:auto;} #msg {width:330px;}</style> <script>var socket; function init(){  var host = "ws://10.3.18.105:19887/";  try{    socket = new WebSocket(host);    socket.onopen    = function(msg){ ; };    socket.onmessage = function(msg){ log(msg.data); };    socket.onclose   = function(msg){ log("Lose Connection!"); };  }  catch(ex){ log(ex); }  $("msg").focus();} function send(){  var txt,msg;  txt = $("msg");  msg = txt.value;  if(!msg){ alert("Message can not be empty"); return; }  txt.value="";  txt.focus();  try{ socket.send(msg); } catch(ex){ log(ex); }} window.onbeforeunload=function(){    try{        socket.send('quit');        socket.close();        socket=null;    }    catch(ex){        log(ex);    }};  function $(id){ return document.getElementById(id); }function log(msg){ $("log").innerHTML+="<br>"+msg; }function onkey(event){ if(event.keyCode==13){ send(); } }</script> </head><body onload="init()"> <h3>WebSocket</h3> <br><br> <div id="log"></div> <input id="msg" type="textbox" onkeypress="onkey(event)"/> <button onclick="send()">發送</button></body></html>

四、伺服器端server.py

import socketimport structimport hashlibimport threading,randomconnectionlist = {}def sendMessage(message):    global connectionlist    for connection in connectionlist.values():        connection.send("\x00%s\xFF" %message)def deleteconnection(item):    global connectionlist    del connectionlist['connection'+item]class WebSocket(threading.Thread):    def __init__(self, conn, index, name, remote, path="/"):        threading.Thread.__init__(self)        self.conn = conn        self.index = index        self.name = name        self.remote = remote        self.path = path        self.buffer = ""    def run(self):        print 'Socket %s Start!' %self.index        headers = {}        self.handshaken = False        while True:            if self.handshaken == False:                print 'Socket %s Start Handshaken with %s!' %(self.index, self.remote)                self.buffer += self.conn.recv(1024)                if self.buffer.find('\r\n\r\n') != -1:                     header, data = self.buffer.split('\r\n\r\n', 1)                    for line in header.split("\r\n")[1:]:                        key, value = line.split(": ", 1)                        headers[key] = value                    headers["Location"] = "ws://%s%s" %(headers["Host"], self.path)                    print headers                            key1 = headers["Sec-WebSocket-Key1"]                    key2 = headers["Sec-WebSocket-Key2"]                    if len(data) < 8:                        data += self.conn.recv(8-len(data))                    key3 = data[:8]                    self.buffer = data[8:]                    token = self.generate_token(key1, key2, key3)                    handshake = '\HTTP/1.1 101 Web Socket Protocol Handshake\r\n\Upgrade: WebSocket\r\n\Connection: Upgrade\r\n\Sec-WebSocket-Origin: %s\r\n\Sec-WebSocket-Location: %s\r\n\r\n\' %(headers['Origin'], headers['Location'])                    self.conn.send(handshake + token)                    self.handshaken = True                    print 'Socket %s Handshaken with %s success!' %(self.index, self.remote)                    sendMessage('Welcome, ' + self.name + ' !')                else:                    self.buffer += self.conn.recv(64)                    if self.buffer.find("\xFF") != -1:                        s = self.buffer.split("\xFF")[0][1:]                        if s == 'quit':                            print 'Socket %s Logout !' %(self.index)                            sendMessage(self.name + ' Logout')                            deleteconnection(str(self.index))                            self.conn.close()                            break                        else:                            print 'Socket %s Got msg: %s from %s!' %(self.index,s,self.remote)                            sendMessage(self.name + ':' + s)                        self.buffer = ""    def generate_token(self, key1, key2, key3):        num1=int("".join([digit for digit in list(key1) if digit.isdigit()]))        spaces1 = len([char for char in list(key1) if char == " "])        num2 = int("".join([digit for digit in list(key2) if digit.isdigit()]))        spaces2 = len([char for char in list(key2) if char == " "])        combined = struct.pack(">II", num1/spaces1, num2/spaces2) + key3        return hashlib.md5(combined).digest()class WebSocketServer(object):    def __init__(self):        self.socket = None    def begin(self):        print "WebSocketSerber Start!"        self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)        self.socket.bind(("10.3.18.105", 19887))        self.socket.listen(50)        global connectionlist        i = 0        while True:            connection, address = self.socket.accept()            username = address[0]            newSocket = WebSocket(connection, i, username, address)            newSocket.start()            conectionlist['connection'+str(i)] = connection            i = i + 1if __name__ == "__main__":    server = WebSocketServer()    server.begin()
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.