TCP-SERVER FOR GFORTH

 

This is the page for a tcp-server written in the fabulous GForth programming language. It is written as an exercise in Forth, as my first Forth-project, and as a out-of-curiosity project about how low-level sockets are handled in BSD/Unix. It is an alpha-release, but is has passed my non-scientific tests without problems. Testing has been done through some perl-scripts which have been ran on a bunch of clients simultaneously, but these scripts can certainly be improved.

 

The server can be used as a non-blocking single-threaded system or it can run in threaded mode as well. The threaded version is based on my (limited?) understanding of the tasker.fs-library in GForth, but it seems to work well.

 

The server has been tested on Mac/Intel, Mini Mac with PPC, Linux Red Hat 8.0 and FreeBsd 6.3 with gforth (snapshop) version 0.6.9, all 32-bits cpuÕs. The server is based on FFCall, for interfacing with glibc, it has been compiled without problems for me, just configure, make, make test, and then make install.

 

The server is based on BSD-sockets and it contains a library for handling bit-arrays. I think the Windows version of the fd_set (without have done any deep investigations) is based on a byte-array, so it will probably not run on Windows, without rewriting the bit-array-file.

 

To use the server:

 

include tcpserver.fs

 

 

create_default_server_data

8888 open-socket-accept

 

This starts the server with the default settings, port 8888. The word create_default_server_data returns a struct, which look like this:

 

struct

   cell% field sd_inbuffer

   cell% field sd_outbuffer           \ not in use presently

   cell% field sd_inbuffer_size

   cell% field sd_outbuffer_size

   cell% field sd_received_data_length

   cell% field sd_client_data

   cell% field sd_time_struct

   cell% field sd_callback_response

   cell% field sd_callback_accept

end-struct server-data

 

The default in-buffer is small, only 100 bytes, allocate larger room and change the struct if needed. The struct contains the pointer to the buffer.

 

After data is received the data is located at the address of the sd_inbuffer, the length is in sd_receifed_data_length.

 

Callbacks are normal forth words. The connection words should defined like this:

 

: socket-accepted ( fid sd -- )

   multi-server

   { fd }

  ." Socket accepted on port: " . cr

  ." Connection from: " fd sd_client_data @ sin_addr @ hex . decimal cr

;

 

The word multi-server can be omitted, it a single threaded version of the server is wanted. The word PAUSE is needed to change focus to another thread.

 

Callback for response to client is something like send-socket-line (this is the default word to be overritten). This word read input from the inbuffer, and sends a reply back to the client.

 

: send-socket-line ( fid sd -- )

        multi-server

        { sd }

        sd sd_inbuffer @ sd sd_received_data_length @ type

        dup s\" Hello Major Tom. Are you receiving?\n" 0 send_socket

        dup 0< if abort" Could not send line" endif

        2drop

;

 

Callbacks are set the default Forth way:

 

Ô my-word server-data-struct sd_callback_response !

 

If the server shall close the connection, this can be done with the word 

 

Close-the-socket ( fid -- )

 

Client side closing is handled by the server.

 

Mutable data: The data in the sd-struct is very mutable and it will for sure change after using the threading-word pause. The reason is that all connections are sharing the same sd-struct, if data from this is needed after a thread-switch it should be copied to a new, local struct ahead of the pause-word.

 

 

Versions:

 

0.1 - Contains basic functionality only.

 

Improvements:

 

- The word send_socket should handle data which is longer than the buffer

- Currently the server is based upon this pattern:

 

              Client opens connection

              Server responds and receives data

              Client receives and close connection

 

More advanced patterns like for example receive-send-receive-send will be implemented using sleeping threads in next version.

 

Bugs:

 

Well, this is done on a computerÉ

 

The code:

 

Download from: http://egesund.org/forth/tcpserver.zip

 

There are only two small files, after all this is Forth J

 

Comments and code improvements are appreciated!

 

 

Petter Egesund

 

petter kr¿llalpha egesund.org