A small tutorial about networking. The PF protocol --------------- This is not really a protocol in the sense of 'yet another protocol', but it is PF's native source file format. It works largely like lisp works: everything thats 'readable' is also 'writable'. the works to use are: read-atom ( stream -- atom ) read an atom from a stream write-atom ( atom stream -- ) write an atom to a stream The default separator is a newline. This makes it compatible with a lot of other unix tools. If this doesn't suit your needs, you can use 'write-atom0' which does not send a separator, leaving the formatting up to you. Instead of 'write-atom' it is possible to use 'write-atom-buffered' which will schedule a write to complete in the background. This is absolutely necessary if you have several PF instances communicating with each other such that there are loops in the communication network. Simple named pipes ------------------ Create a named pipe using the unix command: mkfifo /tmp/fifo Then you can use this to communicate between PF instances. On the reader side you do "/tmp/fifo" "r" open-file and on the writer side it is "/tmp/fifo" "w" open-file These commands give stream object that can be passed to 'read-atom' and 'write-atom'. I.e. if you append the words 'constant FIFO' to both lines above, the commands : receive FIFO read-atom ; "( -- atom )" doc and : send FIFO write-atom ; "( atom -- )" doc can be used to create reveiving and sending words respectively. That's all there is to it. You can use the same approach for plain files, i.e. to store some data. Note that this way you can easily generate executable files that are loadable with the 'load' word. Client Sockets -------------- In a similar way you can connect to a TCP server. For example, run netcat -l -p 12345 To set up a simple testing server. So send data to this server, you can create an output connection stream like this: (localhost 12345) "w" open-connect Replacing "w" by "r" gives an input connection. Server Sockets -------------- Server sockets are a little more complicated. A server socket is basicly a device to create new connected streams whenever a client starts a connection. A server socket is just another stream which is created like this: ("" 12345) "r" open-listen appending 'constant SERVER' to put the stream in the SERVER constant a new connection is created as SERVER "r" open-accept just like above, the "r" can be replaced by "w" to create an output connection. The code above just waits until a client attempts a connection. A simpler approach which is enough in some cases is to create a server which accept only a single connection. Since the server stream is not saved, it is discared (closed) and will no longer accept connections. ("" 5555) "r" open-listen # create server socket and wait for connection "r" open-accept # create connection stream constant CONNECTION # put it in a constant Polling ------- Every time you read (or open-accept) from a stream, and there is no input data (or input connection) present, PF will block until data is ready. To avoid this, there is the word 'select-input'. This function takes a list of streams, and a timeout in milliseconds. It returns when there is input activity, or when a timeout occurs. Upon return, it splits the input list into two list: the top one has all the inactive streams, while the 2nd list has all the active streams. A typical usage of this is: - collect all the streams you are watching in a list - call 'select-input' providing this list and a timeout - discard the list of inactive streams - for each stream left over, call your handling routine Unix domain sockets ------------------- For communication between pf sessions on the same host, unix domain sockets can be used. These behave the same as TCP sockets, with the following differences: - single host only - live in the filesystem, i.e. "/tmp/pfsock" - are more secure, since they are governed by filesystem permissions - are more efficient. no network layer overhead. In PF, they are used in the same way as TCP sockets above, but use the words 'open-list-unix' and 'open-connect-unix' instead. For example: "/tmp/my-socket" "r" open-listen-unix and "/tmp/my-socket" "rw" open-connect-unix