Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.forth > #43847 > unrolled thread
| Started by | Julian Fondren <julian.fondren@gmail.com> |
|---|---|
| First post | 2015-11-26 13:14 -0800 |
| Last post | 2015-11-27 08:33 -0800 |
| Articles | 4 — 3 participants |
Back to article view | Back to comp.lang.forth
Writing (web)servers in Forth Julian Fondren <julian.fondren@gmail.com> - 2015-11-26 13:14 -0800
Re: Writing (web)servers in Forth Lars Brinkhoff <lars.spam@nocrew.org> - 2015-11-27 07:47 +0100
Re: Writing (web)servers in Forth Howerd <howerdo@yahoo.co.uk> - 2015-11-27 08:29 -0800
Re: Writing (web)servers in Forth Howerd <howerdo@yahoo.co.uk> - 2015-11-27 08:33 -0800
| From | Julian Fondren <julian.fondren@gmail.com> |
|---|---|
| Date | 2015-11-26 13:14 -0800 |
| Subject | Writing (web)servers in Forth |
| Message-ID | <4e8b252d-3dd6-4e1d-b9b6-0457b8dadaf3@googlegroups.com> |
Hello, clf,
Yes, it's happened again. Someone has written another webserver in
Forth. I know, it's literally the first thing anyone does. Can you
all, possibly, get to work doing something useful instead of putting
another webserver on GitHub?
I confess, this time it's me who wrote one. You can find it here:
https://bitbucket.org/demonview/forth-httpd
The core of this repository is an evolution of the pollserver I
supplied in a previous post to this group. I'll just put the entirety
of pollserver.fs here:
[defined] client 0= [if] abort
class client
: init ( pollfd -- ) remember pollfd and zero out any data structures, etc. ;
: connected ( -- ) pollfd now has a live socket ;
: reap ( -- ) clean up, log death, etc. pollfd will be killed afterwards ;
: update ( -- ) you have input! (or may now write). deal with it ;
end-class
[then]
class pollserver
max-clients 1+ pollfd builds[] pollfds
max-clients 1+ client builds[] clients
: init-with ( socket -- )
max-clients 1+ 0 do
i pollfds init
i pollfds addr i clients socket !
loop max-clients pollfds fd ! ;
: init ( port -- ) server-socket init-with ;
: server ( -- server-socket ) max-clients pollfds fd @ ;
: accept? ( -- f ) max-clients pollfds ready? ;
: size ( -- n ) 0 max-clients 0 do i pollfds alive? if 1+ then loop ;
DEFER: too-many-connections ( socket -- ) close-file drop ;
: add ( socket -- )
max-clients 0 do
i pollfds dead? if
i pollfds fd !
i clients connected
unloop exit then loop too-many-connections ;
: /accepting ( -- ) accept? if /accept accepted add then ;
: /updating ( -- )
max-clients 0 do
i pollfds alive? if
i pollfds dying? if i clients reap pollfds kill
else i pollfds ready? if i clients update
then then then loop ;
\ 'poll' in these definitions is the syscall
: poll-for ( timeout -- ior ) >r 0 pollfds addr max-clients 1+ r> poll ;
: poll ( -- ior ) 0 pollfds addr max-clients 1+ -1 poll ;
\ 'poll' in this definition is the method
: /serving ( -- )
begin poll 0< abort" poll failed"
/accepting /updating again ;
end-class
That's it. It literally has nothing at all to do with HTTP, or
document roots, or request routing, or 404 errors. It's two arrays,
one fed to poll(), and a mirroring array of client objects. Which
are defined elsewhere. pollserver doesn't even know if clients are
waiting for sockets to be ready for input vs. output. Rather than tie
server logic intimately with with this structure, the direction I was
going in that earlier post, the logic is handled completely by the
client objects.
The repo has a bunch of other stuff, including a README that goes into
other details.
I was impressed, recently, by the Node.js community. You could install
a standalone webserver that would serve static files from the directory
you ran it from, and which had a few options. If you wanted to do a
little more that than, you can do it nearly as rapidly with the Express
framework. If you wanted to get a server running and keep it running,
'forever' was an aptly-named tool for that.
I wasn't as impressed by Node.js itself. For two reasons: my
background is in system administration, and I'd used Erlang before.
So I wrote a little webserver-inna-script for Erlang, too:
https://bitbucket.org/demonview/http-server
And then I found some cheap micro-VPSes, and figured Forth would be
more appropriate for these environments.
Here are a few routes in Express:
var counter = 0
app.get('/counter.fs', function(req, res) {
res.type('text/plain')
res.status(200)
res.send(String(++counter))
})
app.get('/ip.fs', function(req, res) {
res.type('text/plain')
res.status(200)
res.send(req.ip)
})
And the same routes in Forth:
variable counter
simple :: counter-rule
if: m" /counter.fs" ;
do: counter ++ counter @ 0 .r ;
simple :: ip-rule
if: m" /ip.fs" ;
do: client peer @ .ip ;
That's not so bad, is it
Well I'm not a big fan of the :: syntax, but I had a need to create a
statically allocated object and also put its address on the stack, and
SWOOP can do one or the other.
It's a work in progress.
Cheers,
Julian
[toc] | [next] | [standalone]
| From | Lars Brinkhoff <lars.spam@nocrew.org> |
|---|---|
| Date | 2015-11-27 07:47 +0100 |
| Message-ID | <86fuzsrl9m.fsf@vps34351.public.cloudvps.com> |
| In reply to | #43847 |
Julian Fondren <julian.fondren@gmail.com> writes: > [defined] client 0= [if] abort I suggest [undefined].
[toc] | [prev] | [next] | [standalone]
| From | Howerd <howerdo@yahoo.co.uk> |
|---|---|
| Date | 2015-11-27 08:29 -0800 |
| Message-ID | <ff214e2d-d233-49ea-8e33-a574000ef255@googlegroups.com> |
| In reply to | #43847 |
On Thursday, 26 November 2015 21:14:42 UTC, Julian Fondren wrote:
> Hello, clf,
>
> Yes, it's happened again. Someone has written another webserver in
> Forth. I know, it's literally the first thing anyone does. Can you
> all, possibly, get to work doing something useful instead of putting
> another webserver on GitHub?
>
> I confess, this time it's me who wrote one. You can find it here:
> https://bitbucket.org/demonview/forth-httpd
>
> The core of this repository is an evolution of the pollserver I
> supplied in a previous post to this group. I'll just put the entirety
> of pollserver.fs here:
>
> [defined] client 0= [if] abort
> class client
> : init ( pollfd -- ) remember pollfd and zero out any data structures, etc. ;
> : connected ( -- ) pollfd now has a live socket ;
> : reap ( -- ) clean up, log death, etc. pollfd will be killed afterwards ;
> : update ( -- ) you have input! (or may now write). deal with it ;
> end-class
> [then]
>
> class pollserver
> max-clients 1+ pollfd builds[] pollfds
> max-clients 1+ client builds[] clients
>
> : init-with ( socket -- )
> max-clients 1+ 0 do
> i pollfds init
> i pollfds addr i clients socket !
> loop max-clients pollfds fd ! ;
> : init ( port -- ) server-socket init-with ;
>
> : server ( -- server-socket ) max-clients pollfds fd @ ;
> : accept? ( -- f ) max-clients pollfds ready? ;
> : size ( -- n ) 0 max-clients 0 do i pollfds alive? if 1+ then loop ;
>
> DEFER: too-many-connections ( socket -- ) close-file drop ;
> : add ( socket -- )
> max-clients 0 do
> i pollfds dead? if
> i pollfds fd !
> i clients connected
> unloop exit then loop too-many-connections ;
>
> : /accepting ( -- ) accept? if /accept accepted add then ;
> : /updating ( -- )
> max-clients 0 do
> i pollfds alive? if
> i pollfds dying? if i clients reap pollfds kill
> else i pollfds ready? if i clients update
> then then then loop ;
>
> \ 'poll' in these definitions is the syscall
> : poll-for ( timeout -- ior ) >r 0 pollfds addr max-clients 1+ r> poll ;
> : poll ( -- ior ) 0 pollfds addr max-clients 1+ -1 poll ;
>
> \ 'poll' in this definition is the method
> : /serving ( -- )
> begin poll 0< abort" poll failed"
> /accepting /updating again ;
> end-class
>
> That's it. It literally has nothing at all to do with HTTP, or
> document roots, or request routing, or 404 errors. It's two arrays,
> one fed to poll(), and a mirroring array of client objects. Which
> are defined elsewhere. pollserver doesn't even know if clients are
> waiting for sockets to be ready for input vs. output. Rather than tie
> server logic intimately with with this structure, the direction I was
> going in that earlier post, the logic is handled completely by the
> client objects.
>
> The repo has a bunch of other stuff, including a README that goes into
> other details.
>
> I was impressed, recently, by the Node.js community. You could install
> a standalone webserver that would serve static files from the directory
> you ran it from, and which had a few options. If you wanted to do a
> little more that than, you can do it nearly as rapidly with the Express
> framework. If you wanted to get a server running and keep it running,
> 'forever' was an aptly-named tool for that.
>
> I wasn't as impressed by Node.js itself. For two reasons: my
> background is in system administration, and I'd used Erlang before.
>
> So I wrote a little webserver-inna-script for Erlang, too:
>
> https://bitbucket.org/demonview/http-server
>
> And then I found some cheap micro-VPSes, and figured Forth would be
> more appropriate for these environments.
>
> Here are a few routes in Express:
>
> var counter = 0
> app.get('/counter.fs', function(req, res) {
> res.type('text/plain')
> res.status(200)
> res.send(String(++counter))
> })
>
> app.get('/ip.fs', function(req, res) {
> res.type('text/plain')
> res.status(200)
> res.send(req.ip)
> })
>
> And the same routes in Forth:
>
> variable counter
> simple :: counter-rule
> if: m" /counter.fs" ;
> do: counter ++ counter @ 0 .r ;
>
> simple :: ip-rule
> if: m" /ip.fs" ;
> do: client peer @ .ip ;
>
> That's not so bad, is it
>
> Well I'm not a big fan of the :: syntax, but I had a need to create a
> statically allocated object and also put its address on the stack, and
> SWOOP can do one or the other.
>
> It's a work in progress.
>
> Cheers,
> Julian
Hi Julian
Nice one :-)
> Rather than tie server logic intimately with with this structure, the
> direction I was
going in that earlier post, the logic is handled completely by the
client objects.
[toc] | [prev] | [next] | [standalone]
| From | Howerd <howerdo@yahoo.co.uk> |
|---|---|
| Date | 2015-11-27 08:33 -0800 |
| Message-ID | <3f524700-e761-4dd5-927e-e7d82dd57d8b@googlegroups.com> |
| In reply to | #43847 |
On Thursday, 26 November 2015 21:14:42 UTC, Julian Fondren wrote:
> Hello, clf,
>
> Yes, it's happened again. Someone has written another webserver in
> Forth. I know, it's literally the first thing anyone does. Can you
> all, possibly, get to work doing something useful instead of putting
> another webserver on GitHub?
>
> I confess, this time it's me who wrote one. You can find it here:
> https://bitbucket.org/demonview/forth-httpd
>
> The core of this repository is an evolution of the pollserver I
> supplied in a previous post to this group. I'll just put the entirety
> of pollserver.fs here:
>
> [defined] client 0= [if] abort
> class client
> : init ( pollfd -- ) remember pollfd and zero out any data structures, etc. ;
> : connected ( -- ) pollfd now has a live socket ;
> : reap ( -- ) clean up, log death, etc. pollfd will be killed afterwards ;
> : update ( -- ) you have input! (or may now write). deal with it ;
> end-class
> [then]
>
> class pollserver
> max-clients 1+ pollfd builds[] pollfds
> max-clients 1+ client builds[] clients
>
> : init-with ( socket -- )
> max-clients 1+ 0 do
> i pollfds init
> i pollfds addr i clients socket !
> loop max-clients pollfds fd ! ;
> : init ( port -- ) server-socket init-with ;
>
> : server ( -- server-socket ) max-clients pollfds fd @ ;
> : accept? ( -- f ) max-clients pollfds ready? ;
> : size ( -- n ) 0 max-clients 0 do i pollfds alive? if 1+ then loop ;
>
> DEFER: too-many-connections ( socket -- ) close-file drop ;
> : add ( socket -- )
> max-clients 0 do
> i pollfds dead? if
> i pollfds fd !
> i clients connected
> unloop exit then loop too-many-connections ;
>
> : /accepting ( -- ) accept? if /accept accepted add then ;
> : /updating ( -- )
> max-clients 0 do
> i pollfds alive? if
> i pollfds dying? if i clients reap pollfds kill
> else i pollfds ready? if i clients update
> then then then loop ;
>
> \ 'poll' in these definitions is the syscall
> : poll-for ( timeout -- ior ) >r 0 pollfds addr max-clients 1+ r> poll ;
> : poll ( -- ior ) 0 pollfds addr max-clients 1+ -1 poll ;
>
> \ 'poll' in this definition is the method
> : /serving ( -- )
> begin poll 0< abort" poll failed"
> /accepting /updating again ;
> end-class
>
> That's it. It literally has nothing at all to do with HTTP, or
> document roots, or request routing, or 404 errors. It's two arrays,
> one fed to poll(), and a mirroring array of client objects. Which
> are defined elsewhere. pollserver doesn't even know if clients are
> waiting for sockets to be ready for input vs. output. Rather than tie
> server logic intimately with with this structure, the direction I was
> going in that earlier post, the logic is handled completely by the
> client objects.
>
> The repo has a bunch of other stuff, including a README that goes into
> other details.
>
> I was impressed, recently, by the Node.js community. You could install
> a standalone webserver that would serve static files from the directory
> you ran it from, and which had a few options. If you wanted to do a
> little more that than, you can do it nearly as rapidly with the Express
> framework. If you wanted to get a server running and keep it running,
> 'forever' was an aptly-named tool for that.
>
> I wasn't as impressed by Node.js itself. For two reasons: my
> background is in system administration, and I'd used Erlang before.
>
> So I wrote a little webserver-inna-script for Erlang, too:
>
> https://bitbucket.org/demonview/http-server
>
> And then I found some cheap micro-VPSes, and figured Forth would be
> more appropriate for these environments.
>
> Here are a few routes in Express:
>
> var counter = 0
> app.get('/counter.fs', function(req, res) {
> res.type('text/plain')
> res.status(200)
> res.send(String(++counter))
> })
>
> app.get('/ip.fs', function(req, res) {
> res.type('text/plain')
> res.status(200)
> res.send(req.ip)
> })
>
> And the same routes in Forth:
>
> variable counter
> simple :: counter-rule
> if: m" /counter.fs" ;
> do: counter ++ counter @ 0 .r ;
>
> simple :: ip-rule
> if: m" /ip.fs" ;
> do: client peer @ .ip ;
>
> That's not so bad, is it
>
> Well I'm not a big fan of the :: syntax, but I had a need to create a
> statically allocated object and also put its address on the stack, and
> SWOOP can do one or the other.
>
> It's a work in progress.
>
> Cheers,
> Julian
Hi Julian,
Nice one :-)
> Rather than tie
> server logic intimately with with this structure, the direction I was
> going in that earlier post, the logic is handled completely by the
> client objects.
I like this. It sounds like you are following the Forth principle of solving a simpler problem... And if if looks like a webserver, walks like a webserver and sounds like a webserver, then it *is* a webserver.
Best regards,
Howerd
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.forth
csiph-web