基于Html5 websocket和Python的在线聊天室
2012-03-29 16:04
465 查看
一、什么是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),客户端发送数据格式类似这样:
握手协议: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
四、服务器端server.py
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.1 Upgrade: WebSocket Connection: Upgrade Host: www.zendstudio.net:9108 Origin: http://www.zendstudio.net Cookie: somenterCookie这很是有些类似于http的头信息,同样每行都是以”\r\n”结尾的,上面这段格式无需我们去构造,WebSocket对象会自动发送,对客户端这是透明的。此时服务端应该返回的信息是:
HTTP/1.1 101 Web Socket Protocol Handshake Upgrade: WebSocket Connection: Upgrade WebSocket-Origin: http://www.zendstudio.net WebSocket-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 socket import struct import hashlib import threading,random connectionlist = {} 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 + 1 if __name__ == "__main__": server = WebSocketServer() server.begin()
相关文章推荐
- 基于web的服务器push技术:comet vs websocket(HTML5)
- 基于HTML5 WebSocket的Web实时通信机制的研究与实现
- 基于tomcat运行HTML5 WebSocket echo例子
- php基于websocket实现的在线聊天室
- php+html5基于websocket实现聊天室的方法
- 通过(Node Js||.Net)基于HTML5的WebSocket实现实时视频文字传输(上)
- html5-websocket基于远程方法调用的数据交互实现
- 基于html5 localStorage , web SQL, websocket的简单聊天程序
- 通过(Node Js||.Net)基于HTML5的WebSocket实现实时视频文字传输(上)
- HTML5基于Tomcat 7.0实现WebSocket连接并实现简单的实时聊天
- 基于html5 WebSocket和WebRTC实现IM和视音频呼叫(一)
- [转]通过(Node Js||.Net)基于HTML5的WebSocket实现实时视频文字传输(上)
- 基于html5 WebSocket和WebRTC实现IM和视音频呼叫(一)
- 基于html5和nodejs相结合实现websocket即使通讯
- 基于python的websocket开发,tomcat日志web页面实时打印监控案例
- 通过(Node Js||.Net)基于HTML5的WebSocket实现实时视频文字传输1
- 基于html5 WebSocket和WebRTC实现IM和视音频呼叫(二)
- 基于tomcat运行HTML5 WebSocket echo例子
- 基于html5 WebSocket和WebRTC实现IM和视音频呼叫(二)
- 基于HTML5 WebSocket,JavaEE 7在线聊天系统