Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Keeping the WebSocket connection alive

I'm doing a study on WebSocket protocol and trying to implement a simple ECHO service for now with Python on the backend. It seems to work fine but the connection drops right after being established.

Here is my client:

<!doctype html>
<head>
<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript">
function Client()
{
    //var ws = new WebSocket("ws://echo.websocket.org"); // this works fine
    var ws = new WebSocket("ws://localhost:8000");
    ws.onopen = function(e){ $("#response").append(">> Connected<br />"); }
    ws.onclose = function(e){ $("#response").append(">> Disconnected<br />"); }
    ws.onerror = function(e){ $("#response").append(">> ERROR: " + e.data + "<br />"); }
    ws.onmessage = function(e){ $("#response").append("> " + e.data + "<br />"); }

    this.sendCmd = function()
    {
        var message = $("#cmd").val();
        $("#response").append(message + "<br />");
        ws.send(message);
        return false;
    }

    this.disconnect = function()
    {
        ws.close();
    }
}

// onload
$(function() {
    $("#response").append(">> Connecting<br />");

    client = new Client();

    $("#send").click(client.sendCmd);
    $("#disconnect").click(client.disconnect);
});
</script>
</head>
<body>
<input type="text" name="cmd" id="cmd" /> | <a href="#" id="send">Send</a> | <a href="#" id="disconnect">Disconnect</a><br />
<hr />
<span id="response"></span>
</body>
</html>

Here is the server:

import SocketServer
import socket
from hashlib import sha1
from base64 import b64encode

PORT = 8000
MAGIC = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"

class Handler(SocketServer.BaseRequestHandler):
    # incoming connection
    def setup(self):
        self.data = self.request.recv(1024).strip()
        print "connection established", self.client_address
        self.headers = self.headsToDict(self.data.split("\n"))

    # incoming message
    def handle(self):
        # its a handshake
        if "Upgrade" in self.headers and self.headers["Upgrade"] == "websocket":
            key = self.headers["Sec-WebSocket-Key"]
            accept = b64encode(sha1(key + MAGIC).hexdigest().decode('hex'))
            response = "HTTP/1.1 101 Web Socket Protocol Handshake\r\n" # "HTTP/1.1 101 Switching Protocols\r\n"
            print "< HTTP/1.1 101 Web Socket Protocol Handshake" # "HTTP/1.1 101 Switching Protocols\r\n"
            response += "Upgrade: websocket\r\n"
            print "< Upgrade: websocket"
            response += "Connection: Upgrade\r\n"
            print "< Connection: Upgrade"
            response += "Sec-WebSocket-Accept: "+accept+"\r\n\r\n"
            print "< Sec-WebSocket-Accept: "+accept
            self.request.send(response)
        # its a normal message, echo it back
        else:
            print self.data
            self.request.send(self.data)

    # connection dropped
    def finish(self):
        print "connection lost", self.client_address

    # convert a list of headers to a dictionary for convenience 
    def headsToDict(self, hdata):
        rzygi = {}
        for item in hdata:
            print '>', item
            item = item.split(':')
            if len(item) > 1:
                rzygi[item[0].strip()] = item[1].strip()
        return rzygi

server = SocketServer.TCPServer(("", PORT), Handler)
server.socket_type = socket.SOCK_STREAM # didnt help
print "serving at port", PORT
try:
    server.serve_forever()
except KeyboardInterrupt:
    pass
server.server_close()

As mentioned, the connection is established successfully but then drops straight away, which makes me think the code is correct but there is something missing to keep the socket open. Here is the server output:

serving at port 8000
connection established ('127.0.0.1', 52633)
> GET / HTTP/1.1
> Upgrade: websocket
> Connection: Upgrade
> Host: localhost:8000
> Sec-WebSocket-Origin: http://localhost
> Sec-WebSocket-Key: qWGnhdFQ6l8Xs9awgQURfA==
> Sec-WebSocket-Version: 8
< HTTP/1.1 101 Web Socket Protocol Handshake
< Upgrade: websocket
< Connection: Upgrade
< Sec-WebSocket-Accept: fei4E4LQvPnf4y2ilebVsxRofvc=
connection lost ('127.0.0.1', 52633)

How do I keep the socket open?


edit: server code comments

like image 789
Dreen Avatar asked Nov 21 '11 21:11

Dreen


1 Answers

The connection is closed each time after handle. You should rather stay there reading incoming data:

# incoming connection
def setup(self):
    print "connection established", self.client_address

def handle(self):
    while 1:
        try:
            self.data = self.request.recv(1024).strip()

            # incoming message
            self.headers = self.headsToDict(self.data.split("\r\n"))

            # its a handshake
            if "Upgrade" in self.headers and self.headers["Upgrade"] == "websocket":
                key = self.headers["Sec-WebSocket-Key"]
                accept = b64encode(sha1(key + MAGIC).hexdigest().decode('hex'))
                response = "HTTP/1.1 101 Switching Protocols\r\n"
                response += "Upgrade: websocket\r\n"
                response += "Connection: Upgrade\r\n"
                response += "Sec-WebSocket-Accept: "+accept+"\r\n\r\n"
                print response
                self.request.send(response)
            # its a normal message, echo it back
            else:
                print self.data
                self.request.send(self.data)
        except:
            print "except"
            break
like image 123
pimvdb Avatar answered Nov 10 '22 01:11

pimvdb