Examples





Some straightforward examples.




Very simple TCP client example.

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



Very simple TCP server example.

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



Multitasked TCP client example.

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



Simple TCP server example.

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