Some straightforward examples.
Shows usage of basic words.
\ ========================================================================= include ../src/sockets.fs -1 Value mysock s" localhost" 7624 EndPoint: remote known-ip : (client) TCP socket throw to mysock remote mysock connects throw cr ." Connected to server" cr s" Hello TCP World!" mysock sends throw . mysock closes throw ; : client ['] (client) catch dup errno-base < if .errno-excp else throw then ; client
Shows non-blocking use of sockets. Child sockets are blocking even if the master is not. recv-mt returns when something is available, even if we asked to read BufSize bytes.
\ ========================================================================= include ../src/sockets.fs -1 Value master -1 Value slave 7624 EndPoint: local any-ip EndPoint: remote unknown-ip 256 Constant BufSize BufSize Buffer: RxBuffer : (server) TCP socket throw to master local master binds throw master listens throw remote master accepts-mt throw to slave slave -blocking throw cr ." A client has connected" cr RxBuffer BufSize slave recvs-mt throw RxBuffer swap type cr ; : server ['] (server) catch dup errno-base < if .errno-excp else throw then ; server
This example shows a multitasked client using the VFX preemptive multitasker. Upon starting the client, the Forth console is still available and active tasks are shown using multitasker's .tasks word.
I/O through sockets is done using a GENIO /SockDev driver, so words like cr, type, or accept are available. Note that this example does not use event passing nor messages, so there is no need to call pause and blocking sockets are used. Also note that wihin the task, text can be printed in the console surronded by a [io, io] context.
\ ========================================================================= include /usr/share/doc/VfxForth/Lib/Lin32/MultiLin32.fth include ../src/sockets.fs include ../src/Genio/sockets.fs 0 Constant myflags s" localhost" 7624 EndPoint: remote known-ip \ the "remote" end point SockDev: mysock \ ----------------------------------------- : default-io \ -- ; set up default I/O xconsole setIO ; : suicide pause termThread 0 pthread_exit ; : run-task \ xt -- \ wrapper around real task code given by xt catch default-io dup errno-base <= if dup .errno-excp then suicide ; \ ------------------------------------------------------- : .connect cr ." Connected to server " cr ; : .selfmsg \ -- ." task " self ." sent a message" cr ; : task1-init mysock SetIO remote -1 myflags open-gen throw drop [io default-io .connect io] ; : (task1-action) task1-init begin s" Hello TCP World!" type cr \ send to remote [io default-io .selfmsg io] 3000 ms again ; : task1-action ['] (task1-action) run-task ; \ ------------------------------------------------------ task task1 ' task1-action task1 initiate
This example shows a multitasked server using the VFX preemptive multitasker. A master server thread is created to listen to incoming connections and spawns dynamically created slave threads. Slave threads get the text from a client and print it in the Forth console.
I/O through sockets is done using a GENIO /SockDev driver, so words like cr, type, or accept are available. Note that this example does not use event passing nor messages, so there is no need to call pause and blocking sockets are used. When remote clients close connections, slave tasks print exceptions and die. Upon starting the server, the Forth console is still available and active tasks are shown using multitasker's .tasks word.
\ ========================================================================= include /usr/share/doc/VfxForth/Lib/Lin32/MultiLin32.fth include ../src/sockets.fs include ../src/Genio/sockets.fs SOCKDEV_SVR Constant myflags -1 Value master \ master listening socket fd 7624 EndPoint: local any-ip EndPoint: remote unknown-ip 256 Constant BufSize BufSize +User RxBuffer \ slave tasks reception buffers \ ------------------------------------------------------------ variable sock-sid \ shared between tasks semaphore sock-sem \ to syncronize access : sock-sid@ \ -- sid sock-sem request sock-sid @ sock-sem signal ; : sock-sid! \ sid -- sock-sem request sock-sid ! sock-sem signal ; \ ------------------------------------------------------------ \ COMMON WORDS \ ------------------------------------------------------------ : default-io \ The default Forth console I/O xconsole SetIO ; : suicide \ The way a task terminates itself cleanly pause termThread 0 pthread_exit ; : is-action \ xt -- ; wrapper around real action code given by xt catch default-io dup errno-base <= if .errno-excp else drop then suicide ; \ ------------------------------------------------------------ \ SLAVE TASKS \ ------------------------------------------------------------ : new-task \ -- tcb ; creates an unnamed, dynamically allocated task /TCB protAlloc dup initTCB ; : .selfmsg \ #nread -- dup if ." task " self . RxBuffer swap type cr else ." Read 0!" cr then ; : (slave-task) \ slave task action sock-sid@ setIO begin RxBuffer BufSize accept [io default-io .selfmsg io] again ; : slave-task \ slave task wrapper ['] (slave-task) is-action ; \ ------------------------------------------------------------ \ MASTER TASK \ ------------------------------------------------------------ : new-master \ creates the master socket, in blocking mode TCP socket throw to master local master binds throw master listens throw ; : new-sockdev \ -- sid ; dinamically allocated /sockdev /SockDev protAlloc dup initSockDev ; : .connect cr ." A client has connected " cr ; : (server) \ Main server action new-master begin new-sockdev dup >r sock-sid! remote master myflags r> open-gio throw .connect ['] slave-task new-task initiate again ; : server ['] (server) is-action ; : myshutdown sock-sem ShutSem ; \ Main task creation and startup. Leaves a fully operating Forth console sock-sem InitSem task server-task ' server server-task initiate ' myshutdown AtExit