Update RPC with simpler methods for connecting

This commit is contained in:
Jason Paryani
2013-12-12 11:55:50 -08:00
parent 174ecd5609
commit f9bb12bff9
6 changed files with 24 additions and 82 deletions

View File

@@ -1814,13 +1814,16 @@ cdef class TwoPartyServer:
try: try:
self.on_disconnect().wait() self.on_disconnect().wait()
(clientsocket, address) = self._server_socket.accept() (clientsocket, address) = self._server_socket.accept()
self._orig_stream = clientsocket
self._stream = _FdAsyncIoStream(clientsocket.fileno()) self._stream = _FdAsyncIoStream(clientsocket.fileno())
self._network = _TwoPartyVatNetwork()._init(deref(self._stream.thisptr), capnp.SERVER) self._network = _TwoPartyVatNetwork()._init(deref(self._stream.thisptr), capnp.SERVER)
self.thisptr = new RpcSystem(makeRpcServer(deref(self._network.thisptr), deref(self._restorer.thisptr))) self.thisptr = new RpcSystem(makeRpcServer(deref(self._network.thisptr), deref(self._restorer.thisptr)))
Py_INCREF(self._orig_stream)
Py_INCREF(self._stream)
Py_INCREF(self._network) # TODO:MEMORY: attach this to onDrained, also figure out what's leaking
except KeyboardInterrupt: except KeyboardInterrupt:
break break
# TODO: add restore functionality here? # TODO: add restore functionality here?
cdef class _FdAsyncIoStream: cdef class _FdAsyncIoStream:

View File

@@ -1,6 +1,6 @@
.. capnp documentation master file .. capnp documentation master file
Welcome to capnp's documentation! Welcome to pycapnp's documentation!
================================= =================================
This is a python wrapping of the C++ implementation of the `Cap'n Proto <http://kentonv.github.io/capnproto/>`_ library. Here is a short description, quoted from its docs: This is a python wrapping of the C++ implementation of the `Cap'n Proto <http://kentonv.github.io/capnproto/>`_ library. Here is a short description, quoted from its docs:

View File

@@ -28,7 +28,7 @@ On some systems you will have to install Python's headers before doing any of th
sudo apt-get install python-dev sudo apt-get install python-dev
You can control what compiler is used with the environment variable CC, ie. `CC=gcc-4.8 pip install pycapnp`. You only need to run the setuptools line if you have a setuptools older than v0.8.0, and the cython line if you have a version older than v0.19.1. You can control what compiler is used with the environment variable CC, ie. `CC=gcc-4.8 pip install pycapnp`, and flags with CCFLAGS. You only need to run the setuptools line if you have a setuptools older than v0.8.0, and the cython line if you have a version older than v0.19.1.
From Source From Source
--------------------- ---------------------
@@ -43,8 +43,6 @@ or::
cd pycapnp cd pycapnp
python setup.py install python setup.py install
If you don't use pip, you will need to manually install Cython, and a setuptools with a version >= .8.
Development Development
------------------- -------------------

View File

@@ -303,29 +303,21 @@ The examples below will be using `calculator.capnp <https://github.com/jparyani/
Client Client
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
Making a socket Starting a CLient
################ ################
Before you do anything, you'll need to create a connection to the server. You can use anything that is socket-like and has a `fileno` member function, and below we'll just use the :py:mod:`socket` module:: Starting a client is very easy::
import socket
host = 'localhost'
port = 60000
sock = socket.create_connection((host, port))
# Optionally set TCP_NODELAY to disable Nagle's algorithm and speed up RPC
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
Restore Methods
################
Now that you have a socket, it's very easy to connect::
import capnp import capnp
import calculator_capnp import calculator_capnp
client = capnp.TwoPartyClient(sock) client = capnp.TwoPartyClient('localhost:60000')
Restoring
###################
Before you do anything else, you will need to restore a capability from the server. Refer to the `Cap'n Proto docs <http://kentonv.github.io/capnproto/rpc.html>`_ if you don't know what this means::
calculator = client.ez_restore('calculator').cast_as(calculator_capnp.Calculator) calculator = client.ez_restore('calculator').cast_as(calculator_capnp.Calculator)
There's two things worth noting here. First, we used the simpler `ez_restore` function. For servers that use a struct type as their Restorer, you will have to do the following instead:: There's two things worth noting here. First, we used the simpler `ez_restore` function. For servers that use a struct type as their Restorer, you will have to do the following instead::
@@ -383,35 +375,18 @@ You can also chain promises with `then` and the same pipelining will occur::
Server Server
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~
Making a socket
#################
Again, any socket-like object will work, but here's how to do it with the :py:mod:`socket` module::
host = '' # this will bind to all interfaces
port = 60000
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Optionally set TCP_NODELAY on socket to disable Nagle's algorithm
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
s.bind((host, port))
s.listen(1) # service only 1 client at a time
Then, you will have to accept connections one at a time::
(sock, address) = s.accept()
Starting a Server Starting a Server
################## ##################
Once you have a socket, it's quite simple to start a server:: Once you have a socket, it's quite simple to start a server::
server = capnp.TwoPartyServer(sock, restore) server = capnp.TwoPartyServer('*:60000', restore)
server.run_forever() server.run_forever()
See the `Restore`_ section See the `Restore`_ section for an explanation of what the `restore` object needs to looks like.
.. note:: You can also pass a socket with a `fileno()` method to TwoPartyServer. In that case, `run_forever` will not work, and you will have to use `on_disconnect.wait()`.
Implementing a Server Implementing a Server
####################### #######################

View File

@@ -32,8 +32,8 @@ at the given address and does some RPCs')
return parser.parse_args() return parser.parse_args()
def main(sock): def main(host):
client = capnp.TwoPartyClient(sock) client = capnp.TwoPartyClient(host)
# Pass "calculator" to ez_restore (there's also a `restore` function that # Pass "calculator" to ez_restore (there's also a `restore` function that
# takes a struct or AnyPointer as an argument), and then cast the returned # takes a struct or AnyPointer as an argument), and then cast the returned
@@ -282,11 +282,4 @@ def main(sock):
print("PASS") print("PASS")
if __name__ == '__main__': if __name__ == '__main__':
host, port = parse_args().host.split(':') main(parse_args().host)
sock = socket.create_connection((host, port))
# Set TCP_NODELAY on socket to disable Nagle's algorithm. This is not
# neccessary, but it speeds things up.
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
main(sock)

View File

@@ -138,35 +138,8 @@ def restore(ref):
def main(): def main():
address = parse_args().address address = parse_args().address
if ':' in address: server = capnp.TwoPartyServer(address, restore)
address, port = address.split(':')
port = int(port)
else:
port = random.randint(60000, 61000)
if address == '*':
address = ''
print("Listening on port: {}".format(port))
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Set TCP_NODELAY on socket to disable Nagle's algorithm. This is not
# neccessary, but it speeds things up.
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
s.bind((address, port))
s.listen(1) # service only 1 client at a time
while True:
try:
(clientsocket, address) = s.accept()
server = capnp.TwoPartyServer(clientsocket, restore)
server.run_forever() server.run_forever()
print("client disconnected")
except KeyboardInterrupt:
break
if __name__ == '__main__': if __name__ == '__main__':
main() main()