On 13/11/2023 17:42, Mark Moulding wrote (cross-posted from the Discussion Group):
The way that @DDRM has describes echos my experience writing a specialized web server in Microsoft Visual Basic....
Note that there is no need for multi-threading - although it can be done in VB6, it's quite a hassle, and quite unnecessary in most cases; the event-driven model works as well.
Exactly, multi-threading is one way to do it, and in many languages it is probably the best way, but it is not the
only way.
It is necessary to monitor all active ports for data arrival; I could see doing this by attempting a non-blocking read on each active port in turn, but this seems like a very inefficient use of CPU. I expect that Richard can suggest a better way.
Not really. BBC BASIC is not an 'event driven' language, I doubt that the concept had even been devised in 1981! So the only practical way to implement concurrency is a polling method such as you describe. To get a feel for the potential inefficiency I've just done a quick test of how long
FN_readsocket() takes on this PC, when there is nothing to receive; it appears to be around 60 μs.
Suppose there are 10 concurrent connections, and one wanted to poll them all every 10ms to check for incoming data, that would mean that about 600μs of that 10ms (6%) would be 'wasted' CPU time. I don't think that is too bad, but it does illustrate that the polling approach in an interpreted language like BBC BASIC will limit the number of concurrent connections significantly.
A very limited amount of state information needs to be maintained for each port, at least for a basic (lower case) web server, since HTML at its core is modeless
Indeed, but the OP is not using HTML and I have no idea what amount of state is needed per connection. But an array of structures is an elegant way of representing that state in BBC BASIC.
Regarding Richard's proposal and subsequent discard of multiple tasks to allow the operating system to handle multi-threading, would it be possible to have a master task listening to the primary port for connection requests, which then spawns additional tasks to complete the requests
I've not given it much thought, but I don't think that will work, with the existing SOCKLIB libraries anyway. When the 'listening' socket accepts an incoming connection request, it opens the socket which will be used for that connection, and I don't think there's any way to 'hand over' that socket from one process to another*.
* It appears that it
is possible but one would have to bypass SOCKLIB to achieve that, and thereby lose the cross-platform compatibility.