Today I wanted to try out websockets because I heard that Google Chrome just integrated a preliminary version of it. I discovered that their isn’t a simple straightforward guide for doing this with apache2. Here is a simple guide to getting it working:

Starting with:

  • Ubuntu 9.10 (I think it will work with most recent versions of ubuntu and other distributions will work if you change the package manager commands)
  • Apache2 installed and working (punch sudo apt-get install apache2 into the terminal, type 127.0.0.1 into the browser to check)
  • Python 2.6.x installed and working
  • Subversion

Step 1: Install mod_python and get it working with apache

  1. Punch sudo apt-get install libapache2-mod-python into the terminal
  2. In /etc/apache2/sites-available/default change the part that looks like:
    1
    2
    3
    4
    
      Options Indexes FollowSymLinks MultiViews
      AllowOverride None
      Order allow,deny
      allow from all

    To:

    1
    2
    3
    4
    5
    6
    7
    
      Options Indexes FollowSymLinks MultiViews
      AllowOverride None
      Order allow,deny
      allow from all
      AddHandler mod_python .py
      PythonHandler mod_python.publisher
      PythonDebug On
  3. Restart apache: sudo /etc/init.d/apache2 restart
  4. Test it by throwing something like this into a new file test.py in /var/www:
    1
    2
    
    def index(req):
      return "Test successful"
  5. Navigate to localhost/test.py to see if the test is successful

Step 2: Get and Install pywebsocket

  1. Make sure you have subversion installed and run this in the terminal: svn checkout http://pywebsocket.googlecode.com/svn/trunk/ pywebsocket-read-only
  2. Now navigate into the pywebsocket-read-only folder where you downloaded it … aka cd pywebsocket-read-only
  3. Run sudo python setup.py build
  4. Then sudo python setup.py install
  5. Make a directory for the handlers … I made mine in my home directory as you can see below
  6. Now edit /etc/apache2/httpd.conf to include the following:
    1
    2
    3
    4
    5
    
      PythonPath "sys.path+['/usr/local/lib/python2.6/dist-packages/mod_pywebsocket']"
     
      PythonOption mod_pywebsocket.handler_root /home/travis/Desktop/websock_handlers
     
      PythonHeaderParserHandler mod_pywebsocket.headerparserhandler

    The first path /usr/local/lib/python2.6/dist-packages/mod_pywebsocket is where you installed mod_pywebsocket and should be in a similar location for you.

    The second path /home/travis/Desktop/websock_handlers is where I put my handlers directory.

    Remember to change the paths to fit your implementation

Step 3: Make some handlers where you said they would be above and you should be all set

 

The title’s a mouth full but the problem is very interesting and not too hard to break down.

  • Runge Kutta is a numerical method technique very usefull for solving ordinary differential equations on computers
  • HTML5 is the new html specification currently being implemented by browsers that allows many new things including:
    • Use of canvas objects (2D drawing on the web, see below)
    • Websockets (persistent connections between clients and servers)
    • Video and Audio

What I’ve done is use a combination of the html canvas tools with the runge kutta technique implemented in javascript to show two masses/objects orbiting eachother. You can do a bunch of neat things with this including processing orbits etc. Check it out:

Javascript code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
$(document).ready(function() {
      //get a reference to the canvas
	  ctx = $('#canvas')[0].getContext("2d");
	  ax=100.0;
	  ay=200.0;
	  bx=200.0;
	  by=100.0;
	  adx=1;
	  ady=1;
	  bdx=-1;
	  bdy=-1;
	  time_step=1;
      setInterval(draw, 10);
    });
 
    // runge kutta gravitational advance
    function f(p1,p2,dist){
      var g=.05;
      return g*(1/dist^2)*((p2-p1)/dist);
    }
 
	function draw() {
 
	  // stop iterating if they collide
	  var dist=distance(ax,ay,bx,by);
	  if(!dist<10){
 
	    k1_adx=f(ax,bx,dist);
		k2_adx=f(ax+time_step/2*k1_adx,bx,dist);
		k3_adx=f(ax+time_step/2*k2_adx,bx,dist);
		k4_adx=f(ax+time_step*k3_adx,bx,dist);
        adx+=time_step*(k1_adx+2*(k2_adx+k3_adx)+k4_adx)/6;
 
        k1_ady=f(ay,by,dist);
	    k2_ady=f(ay+time_step/2*k1_ady,by,dist);
	    k3_ady=f(ay+time_step/2*k2_ady,by,dist);
		k4_ady=f(ay+time_step*k3_ady,by,dist);
        ady+=time_step*(k1_ady+2*(k2_ady+k3_ady)+k4_ady)/6;
 
        k1_bdx=f(bx,ax,dist);
		k2_bdx=f(bx+time_step/2*k1_bdx,ax,dist);
		k3_bdx=f(bx+time_step/2*k2_bdx,ax,dist);
		k4_bdx=f(bx+time_step*k3_bdx,ax,dist);
		bdx+=time_step*(k1_bdx+2*(k2_bdx+k3_bdx)+k4_bdx)/6;
 
		k1_bdy=f(by,ay,dist);
		k2_bdy=f(by+time_step/2*k1_bdy,ay,dist);
		k3_bdy=f(by+time_step/2*k2_bdy,ay,dist);
		k4_bdy=f(by+time_step*k3_bdy,ay,dist);
        bdy+=time_step*(k1_bdy+2*(k2_bdy+k3_bdy)+k4_bdy)/6;
 
      }
      else{
        console.log("stop moving\n");
      }
	  // update positions
	  ax += adx;
	  ay += ady;
	  bx += bdx;
	  by += bdy;
 
	  ctx.clearRect(0,0,1000,800);
	  ctx.beginPath();
	  ctx.arc(ax, ay, 10, 0, Math.PI*2, true);
	  ctx.closePath();
	  ctx.fill();
	  ctx.beginPath();
	  ctx.arc(bx, by, 10, 0, Math.PI*2, true);
	  ctx.closePath();
	  ctx.fill();
    }
 
    function distance(x1,y1,x2,y2){
      return Math.sqrt(Math.pow(x2-x1,2)+Math.pow(y2-y1,2));
    }
Tagged with: