Chapter 18 ■ rpC
341
from jsonrpclib import Server
def main():
proxy = Server('http://localhost:7002')
print(proxy.lengths((1,2,3), 27, {'Sirius': -1.46, 'Rigel': 0.12}))
if name == 'main':
main()
Writing client code is also quite simple. Sending several objects whose lengths you want measured—and
having those data structures echoed right back by the server—enables you to see several details about this particular
protocol.
First, note that the protocol allows you to send as many arguments as you want; it was not bothered by the fact
that it could not introspect a static method signature from the function. This is similar to XML-RPC, but it is very
different from XML-RPC mechanisms built for traditional, statically typed languages.
Second, note that the None value in the server’s reply passes back unhindered. This is because this value is
supported natively by the protocol itself, without having to activate any nonstandard extensions:
$ python jsonrpc_server.py
Starting server
[In another command window:]
$ python jsonrpc_client.py
[[3, [1, 2, 3]], [None, 27], [2, {'Rigel': 0.12, 'Sirius': -1.46}]]
Third, note that there is only one kind of sequence supported by JSON-RPC, which means that the tuple sent by
the client had to be coerced to a list to make it across.
Of course the biggest difference between JSON-RPC and XML-RPC—that the data payload in this case is a small,
sleek JSON message that knows natively how to represent each of the data types—is not even visible here. This is
because both mechanisms do such a good job of hiding the network from the code. When running Wireshark on my
localhost interface while running this example client and server, I can see that the actual messages being passed are as
follows:
{"version": "1.1",
"params": [[1, 2, 3], 27, {"Rigel": 0.12, "Sirius": -1.46}],
"method": "lengths"}
{"result": [[3, [1, 2, 3]], [null, 27],
[2, {"Rigel": 0.12, "Sirius": -1.46}]]}
Note that the popularity of JSON-RPC version 1 has led to several competing attempts to extend and supplement
the protocol with additional features. You can do research online if you want to explore the current state of the
standard and the conversation around it. For most basic tasks, you can simply use a good third-party Python
implementation and not worry about the debate over extensions to the standard.
It would be remiss of me to leave this topic without mentioning one important fact. Although the preceding
example is synchronous—the client sends a request and then waits patiently to receive only a single response and
does nothing useful in the meantime—the JSON-RPC protocol does support attaching id values to each request.
This means that you can have several requests under way before receiving any matching responses back with the
same id attached. I will not explore the idea any further here because asynchrony, strictly speaking, goes beyond
the traditional role of an RPC mechanism. Function calls in traditional procedural languages are, after all, strictly
synchronous events. However, if you find the idea interesting, you should read the standard and then explore which
Python JSON-RPC libraries might support your need for asynchrony.