Client Server Basics

Using the build-in PF client-server system

When you want to send and receive data that is not suitable for Open Sound Control, you can work with PF's build in client-server system.

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 words to use are:

read-atom         ( stream -- atom )  read an atom from a stream
write-atom        ( atom stream -- )  write an atom to a stream

Client Sockets

You can connect to a TCP server. To test this, use the following unix command to set up a testing server:

netcat -l -p 12345

To create an output connection stream, start pf and type:

(localhost 12345) "w" open-connect

Replacing "w" by "r" gives an input connection.

Server sockets

A server socket is basicly a device to create new connected streams whenever a client starts a connection. Start the connection like this:

("" 12345) "r" open-listen               # create stream
constant SERVER                          # store it in a constant
SERVER "r" open-accept                   # create the connection

For more information about networking in PF, you can read the networking.txt in libpf's doc section.

An example using input-select

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 received. To avoid PF from blocking all other running processes, there is the word 'select-input'. This function takes a list of streams, and a timeout in milliseconds. So if there is no input, it simply times out, without blocking your other processes. input-select splits the input list into two lists: the top one has all the inactive streams, while the 2nd list has all the active streams. To see it in action, try running these 2 scripts (start the server first, then the client):

The server:

load-opengl
200 200 display
2d
animation

0. variable! flag
0 :: 1 + ; counter count
0. variable! STREAMS                          

("" 12345) "r" open-listen                     # create stream
constant SERVER                                # store stream in constant
SERVER "r" open-accept                         # start the connection
dup 1 pack STREAMS !                           # put stream in a list 
constant CONNECTION                            # and store it in a constant

: handle-stream
        CONNECTION read-atom . ;               # prints incoming data
: catch
        STREAMS @ 0.0 select-input             # 0 milliseconds timeout
        drop ' handle-stream for-each ;        # drop inactive streams and handle
                                               # all active streams in list
: anim
        catch                                  # executes catch
        1. rand square                         # pf executes other words
        ;

:: anim ; is drawer                                    

The client:

load-opengl
200 200 display
2d
animation

0. variable! flag
0 :: 1 + ; counter count

(localhost 12345) "w" open-connect              # start (writing) connection
constant network                                # store it in a constant

: send
        flag @ 100 mod 0 = if                   # every 100 frames a random
        10. rand network write-atom             # number gets send 
        then ;
: anim
        count flag !                            # update counter
        send                                    # send gets executed
        0.01 square ;                           # pf executes other words 
                                                

:: anim ; is drawer