deavid edited this page Dec 27, 2010 · 17 revisions
Clone this wiki locally


BJSONRPC (Bidirectional JSON-RPC) is a JSON-RPC implementation in pure python aimed at speed and simplicity.

It's a good replacement to XML-RPC in environments where interactivity is critical.

It follows the JSON-RPC 1.1 specification with several additions.


Currently in development stage. Is fully functional, but API may change.

A beta version will probably be released over February.

Main Features

  • Implemented in pure python
  • TCP/IP Socket based. There is no HTTP version.
  • Connections are permanent and reused for multiple calls.
  • Low bandwith use. (aprox 60 bytes or less per call)
  • Minimal network latency. (with asyncronous calls is possible to use the full bandwith)
  • Methods can be stateful (they can remember what you called before, etc)
  • Allows (and simplifies) asynchronous calls.
  • Event-driven client and server (can be run with no threads at all)
  • Allows keyword parameters to be passed to functions.
  • Bidirectional. Client can also publish methods for server.
  • Object Oriented Programming (OOP). Objects can be created and handled remotely.
  • Client/Server Object Reference. You can create a object in the other end and tell some method to use it.
  • Server Method Reference. You can pass a server method as a parameter to a server function.

  • Features

Simple examples

Server example

import bjsonrpc

class MyHandler(bjsonrpc.BaseHandler):
    def add(self,a,b): return a+b


Client example

import bjsonrpc

conn = bjsonrpc.connect() # defaults to
print conn.call.add(2,3) # prints 5

Raw requests

There are some requests in their raw state over the socket: (< is write to socket , > is readed from socket, numbers in :99: are the message-length)

>>> import bjsonrpc
>>> c = bjsonrpc.connect()
>>> r = c.call.echo("hello world")
>>> c._debug_socket=True # enable debugging output.
>>> r = c.call.echo("hello world")
<:49: {"params":["hello world"],"method":"echo","id":2}
>:44: {"id":2,"result":"hello world","error":null}
>>> l1 = c.call.mewList() # syntax error: **m**ew instead of new
<:27: {"method":"mewList","id":3}
>:73: {"id":3,"result":null,"error":"ValueError(\\"Unkown method 'mewList'\\",)"}
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "../bjsonrpc/proxies.py", line 47, in fn
    return self._conn._proxy(self.sync_type, name, args, kwargs)
  File "../bjsonrpc/connection.py", line 263, in _proxy
    return req.value
  File "../bjsonrpc/request.py", line 79, in value
    raise ServerError(self.response['error'])
ServerError: ValueError("Unkown method 'mewList'",)
>>> l1 = c.call.newList() # this returns a remote object.
<:27: {"method":"newList","id":4}
>:65: {"id":4,"result":{"__remoteobject__":"mylist_0001"},"error":null}
>>> l1.call.add(1) # the remote object has its own methods.
<:48: {"params":[1],"method":"mylist_0001.add","id":5}
>:35: {"id":5,"result":null,"error":null}
>>> l1.call.items()
<:37: {"method":"mylist_0001.items","id":6}
>:34: {"id":6,"result":[1],"error":null}
>>> del l1 # throw away the object in the remote server.
<:42: {"method":"mylist_0001.__delete__","id":7}
>:35: {"id":7,"result":null,"error":null}


You can run a standard benchmark using the example1 client and server. In my home computer (which is 5 years old) it gives the following results:

  • Notify Total: 2.08s 4814.06 req/s
  • Method Total: 1.28s 2347.58 req/s
  • Call Total: 0.32s 1583.29 req/s

The computer at my office (Core 2 Duo) gives about 20K req/s on Notify,10K on Method, 5K on Call.

example1b-client is a specific example for PythonCE for PDA's with Windows Mobile. The numbers are about 120,60,50 req/s.

Over a real network, of course, the numbers are lower because of the latency and bandwidth limitations:

  • Notify and Method are asynchronous calls, so they are bandwith-bounded. Notify should be the twice as faster as Method because it requires no response from server. Expect about 60bytes per call, so in a Internet connection with 300kbit uplink you will be able to handle about 625 requests per second.
  • Call is a syncronous call, so is latency-bounded. In a connection with 80ms latency, a syncronous call would take 160ms, so it's possible to serialize about 375 calls in a minute.

Other pages