Skip to content

Instantly share code, notes, and snippets.

@simonkcleung
Created September 25, 2012 14:21
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save simonkcleung/3782229 to your computer and use it in GitHub Desktop.
Save simonkcleung/3782229 to your computer and use it in GitHub Desktop.
node.js websocket example
var server=require('websocket.js').createServer();
var chatroom=server.addApp('/chatroom');
chatroom.ondata=function(data,userName){
this.broadcast(data,userName);
}
chatroom.onclose=function(userName){
this.broadcast(userName+" disconnected.");
}
chatroom.onconnect=function(userName){
this.broadcast(userName+" connected.");
}
server.listen(8080);
<!docytpe html>
<html>
<head>
<meta charset="UTF-8" />
<title>web socket</title>
<style>
#userinput,#userid{
width:435px;
}
button{
min-width:60px;
}
#disconnectBtn{
display:none;
}
#chatbox{
height:20em;
width:500px;
}
</style>
<script>
"use strict";
var ws,userName,send,userinput,disconnectBtn,chatbox;
window.onload=function(){
var $=document.getElementById.bind(document);
send=$('send');
userinput=$('userinput');
disconnectBtn=$('disconnectBtn');
chatbox=$('chatbox');
}
function disconnect(){
ws.close();
send.textContent='connect';
userinput.value=userName;
disconnectBtn.style.display='';
chatbox.value+='disconnecting...\n';
}
function sendmsg(){
if (!ws || ws.readyState===3){
if (userinput.value){
userName=userinput.value;
ws=new WebSocket("ws://localhost:8080/chatroom?user="+userName);
ws.onopen=function(){
chatbox.value+='connected>\n';
send.textContent='send';
userinput.placeholder='Message';
userinput.value='';
disconnectBtn.style.display='inline-block';
};
ws.onmessage=function(evt){chatbox.value+=evt.data+'\n'};
ws.onerror=function(){chatbox.value+='error>\n'};
ws.onclose=function(){
chatbox.value+='disconnected>\n';
send.textContent='connect';
userinput.value=userName;
userinput.placeholder='User Name';
disconnectBtn.style.display='';
};
}
} else if (ws.readyState===1){
ws.send(userinput.value);
userinput.value='';
}
}
</script>
</head>
<body>
<textarea id="chatbox"></textarea><br/>
<input id="userinput" placeholder="User Name"></input>
<button id="send" onclick="sendmsg()">connect</button>
<br/>
<button id="disconnectBtn" onclick="disconnect()">disconnect</button>
<button onclick="chatbox.value+=['CONNECTING','OPEN','CLOSING','CLOSED'][ws.readyState]+'>\n'">connection state</button>
<button onclick="chatbox.value=''">clear</button>
</body>
</html>
var http=require('http'), crypto=require('crypto'), urlparser=require('url').parse
,HandshakeResponseHead="HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "
,GUI="258EAFA5-E914-47DA-95CA-C5AB0DC85B11", CLOSE_BUFFER=new Buffer([136,2,3,232])
,BUFFERLEN7BITS=new Buffer(2), BUFFERLEN16BITS=new Buffer(4);
BUFFERLEN7BITS[0]=BUFFERLEN16BITS[0]=129;
BUFFERLEN16BITS[1]=126;
module.exports.createServer=function(s){
if (s instanceof http.Server==false) s=http.createServer();
s.on('upgrade',handShake);
s.apps=new Object;
s.addApp=addApp;
return s;
}
function handShake(request,socket){
var header=request.headers,url=urlparser(request.url,true), key;
if (request.method!="GET") return rejectConnection(405,socket);
if (parseFloat(request.httpVersion)<1.1) return rejectConnection(505,socket);
if (url.pathname in this.apps==false) return rejectConnection(404,socket);
if (parseInt(header['sec-websocket-version'],10)<13) return rejectConnection(426,socket);
if (header.upgrade!="websocket") return rejectConnection(406,socket);
key=header['sec-websocket-key'];
if (key){
socket.write(HandshakeResponseHead+crypto.createHash('sha1').update(key+GUI).digest('base64')+ "\r\n\r\n",'ascii');
this.apps[url.pathname].addConnection(socket,url.query.user);
} else rejectConnection(417,socket);
}
function rejectConnection(statusCode,socket){
socket.end('HTTP/1.1 '+statusCode+' '+http.STATUS_CODES[statusCode]+'\r\n\r\n','ascii');
}
function addApp(url){
this.apps[url]=new Application(url);
return this.apps[url];
}
function Application(url){
this.connections=new Object;
}
Application.prototype.addConnection=function(socket,userName){
if (userName in this.connections == false)
this.connections[userName]=new Connection(socket,userName,this);
}
Application.prototype.close=function(userName){
var c=this.connections, s;
if (userName in c){
s=c[userName].socket;
s.end(CLOSE_BUFFER);
s.removeAllListeners();
s.destroy();
delete c[userName];
if (this.onclose) this.onclose(userName);
}
}
Application.prototype.broadcast=function(buffer,userName){
if (typeof buffer =='string') buffer=new Buffer(buffer);
var len=buffer.length, bufferhead, c=this.connections, user , s;
if (userName) {
userName=new Buffer(userName+': ');
len+=userName.length;
}
if (len<126){
bufferhead=BUFFERLEN7BITS;
bufferhead[1]=len;
} else if (len<65536){
headbuffer=BUFFERLEN16BITS;
headbuffer.writeUInt16BE(len,2);
} else return ;
for (user in c){
s=c[user].socket;
s.write(bufferhead);
if (userName) s.write(userName);
s.write(buffer);
}
}
function Connection(socket,userName,app){
function onData(buffer){
var i=2, j, opcode=buffer[0]&15, length=buffer[1]&127;
if (length==127 || opcode==8) return app.close(userName);
if (opcode==1){
if (length==126){
length=buffer.readUInt16BE(2);
i+=2;
}
var maskingKeys=buffer.slice(i,i+=4), payloadData=buffer.slice(i);
for (j=0;j<4;j++)
for (i=j, maskingKey=maskingKeys[j];i<length;i+=4)
payloadData[i]^=maskingKey;
if (app.ondata) app.ondata(payloadData,userName);
}
}
socket.on('data',onData);
this.socket=socket;
if (app.onconnect) app.onconnect(userName);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment