August'24: Kamaelia is in maintenance mode and will recieve periodic updates, about twice a year, primarily targeted around Python 3 and ecosystem compatibility. PRs are always welcome. Latest Release: 1.14.32 (2024/3/24)
These 'chassis' style components are used to implementing connected servers. The most common example of this is a server which runs on top of the TCP. Examples include: a web server, email server, imap server, game protocol server, etc.
At present, there are two variants of this: ServerCore and SimpleServer (You are generally recommended to use ServerCore)
Both of these revolve around building TCP based servers. They handle the mechanics of creating the listening component, and when new connections come in, creating instances of your protocol handler components to handle the connections.
As a result, the primary arguments are the port to listen on and a function call or class name that when called returns a component for handling this connection.
Your protocol handler then receives data from a specific client on its inbox "inbox" and sends data to that same client on its outbox "outbox".
ServerCore passes additional information about the connection to the function that creates the protocol handler. You are not required to do anything with that information if you don't need to.
Aside from that, ServerCore & SimpleServer are used in the same way. (ServerCore is just an extension, and rationalisation of the older simple server code).
There is more information here: http://www.kamaelia.org/Cookbook/TCPSystems
A server using a simple echo protocol, that just echoes back anything sent by the client. Becase the protocol has no need to know any details of the connection, the SimpleServer component is used:
import Axon
from Kamaelia.Chassis.ConnectedServer import SimpleServer
PORTNUMBER = 12345
class EchoProtocol(Axon.Component.component):
def main(self):
while not self.shutdown():
yield 1
if self.dataReady("inbox"):
data = self.recv("inbox")
self.send(data, "outbox")
def shutdown(self):
if self.dataReady("control"):
msg = self.recv("control")
return isinstance(msg, Axon.Ipc.producerFinished)
simpleServer = SimpleServer( protocol = EchoProtocol, port = PORTNUMBER )
simpleServer.run()
Try connecting to this server using the telnet command, and it will echo back to you every character you type.
A more complex server might need to inform the protocol of the IP address and port of the client that connects, or the ip address and port at this (the server end) to which the client has connected. For this, ServerCore is used:
import Axon
from Axon.Ipc import shutdownMicroprocess
from Kamaelia.Chassis.ConnectedServer import ServerCore
PORTNUMBER = 12345
class CleverEchoProtocol(Axon.Component.component):
def main(self):
welcomeMessage = "Welcome! You have connected to %s on port %d from %s on port %d" % (self.localip, self.localport, self.peer, self.peerport)
self.send(welcomeMessage, "outbox")
while not self.shutdown():
yield 1
if self.dataReady("inbox"):
data = self.recv("inbox")
self.send(data, "outbox")
def shutdown(self):
if self.dataReady("control"):
msg = self.recv("control")
return isinstance(msg, Axon.Ipc.producerFinished)
myServer = ServerCore( protocol = CleverEchoProtocol, port = PORTNUMBER )
myServer.run()
Example output when telnetting to this more complex server, assuming both server and telnet session are running on the same host, and the server is listening to port number 8081:
$ telnet localhost 8081
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Welcome! You have connected to 127.0.0.1 on port 8081 from 127.0.0.1 on port 47316
Provides a framework for creating generic protocol handlers to deal with information coming in on a single port (and a single port only). This however covers a large array of server types.
A protocol handler is simply a component that can receive and send data (as byte strings) in a particular format and with a particular behaviour - ie. conforming to a particular protocol.
Provide this chassis with a factory function to create a component to handle the protocol. Whenever a client connects a handler component will then be created to handle communications with that client.
Data received from the client will be sent to the protocol handler component's "inbox" inbox. To send data back to the client, the protocol handler component should send it out of its "outbox" outbox.
For the SingleServer component, the factory function takes no arguments. It should simply return the component that will be used to handle the protocol, for example:
def makeNewProtocolHandler():
return MyProtocolComponent()
For the ServerCore component, the factory function must accept the following arguments (with these names):
For example:
def makeNewProtocolHandler(peer, peerport, localip, localport):
print "Debugging: client at address "+peer+" on port "+str(peerport)
print " ... has connected to address "+localip+" on port "+str(localport)
return MyProtocolComponent()
Do not activate the component. SingleServer or ServerCore will do this once the component is wired up.
A protocol handler component should use its standard inboxes ("inbox" and "control") and outboxes ("outbox" and "signal") to communicate with client it is connected to.
If the connection is closed, a Kamaelia.IPC.socketShutdown message will arrive at the protocol handler's "control" inbox. If this happens then the connection should be assumed to have already closed. Any more messages sent will not be sent to the client. The protocol handler should react by terminating as soon as possible.
To cause the connection to close, send a producerFinished or shutdownMicroprocess message out of the protocol handler's "signal" outbox. As soon as this has been done, it can be assumed that the connection will be closed as soon as is practical. The protocol handler will probably also want to terminate at this point.
SimpleServer is based on ServerCore. It simply contains a wrapper around the protocol handler function that throws away the connection information instead of passing it in as arguments.
At initialisation the component registers a TCPServer component to listen for new connections on the specified port.
You supply a factory function that takes no arguments and returns a new protocol handler component.
When it receives a 'newCSA' message from the TCPServer (via the "_socketactivity" inbox), the factory function is called to create a new protocol handler. The protocol handler's "inbox" inbox and "outbox" outbox are wired to the ConnectedSocketAdapter (CSA) component handling that socket connection, so it can receive and send data.
If a 'shutdownCSA' message is received (via "_socketactivity") then a Kamaelia.IPC.socketShutdown message is sent to the protocol handler's "control" inbox, and both it and the CSA are unwired.
This component does not terminate. It ignores any messages sent to its "control" inbox.
In practice, this component provides no external connectors for your use.
This code is based on the code used for testing the Internet Connection abstraction layer.
This component currently lacks an inbox and corresponding code to allow it to be shut down (in a controlled fashion). Needs a "control" inbox that responds to shutdownMicroprocess messages.
ServerCore(protocol[,port]) -> new Simple protocol server component
A simple single port, multiple connection server, that instantiates a protocol handler component to handle each connection. The function that creates the protocol must access arguments providing information about the connection.
Keyword arguments:
Warning!
You should be using the inbox/outbox interface, not these methods (except construction). This documentation is designed as a roadmap as to their functionalilty for maintainers and new component developers.
x.__init__(...) initializes x; see x.__class__.__doc__ for signature
handleClosedCSA(shutdownCSAMessage) -> None
Terminates and unwires the protocol handler for the closing socket.
Keyword arguments: shutdownCSAMessage -- shutdownCSAMessage.object is the ConnectedSocketAdapter for socket that is closing.
handleNewConnection(newCSAMessage) -> Axon.Ipc.newComponent(protocol handler)
Creates and returns a protocol handler for new connection.
Keyword arguments:
SimpleServer(protocol[,port]) -> new Simple protocol server component
A simple single port, multiple connection server, that instantiates a protocol handler component to handle each connection.
Keyword arguments:
Warning!
You should be using the inbox/outbox interface, not these methods (except construction). This documentation is designed as a roadmap as to their functionalilty for maintainers and new component developers.
Got a problem with the documentation? Something unclear that could be clearer? Want to help improve it? Constructive criticism is very welcome - especially if you can suggest a better rewording!
Please leave you feedback here in reply to the documentation thread in the Kamaelia blog.
-- Automatic documentation generator, 05 Jun 2009 at 03:01:38 UTC/GMT