multiple local sockets

Alex Tweedly alex at tweedly.net
Fri Dec 31 08:50:42 EST 2004


Nicolas Cueto wrote:

>     To enable my (sometimes unduly hesitant!)
>language-learners to interact aurally and visually over the school LAN, I
>want to create a client-stack capable of sending to and receiving from a
>likewise cofigure server-stack both data and stack-events -- and all
>happening live, sometimes simultaneously (e.g., within one card's script),
>and with as few ports/handlers as possible!
>
>"Send-to" taks for the client-stack include:
>- logging-in so that everyone knows who's on-line
>- making requests for various types of data
>- broadcasting local stack events to all or some host stacks
>  
>
If at all possible, I'd make each client talk ONLY to the server. Make
one of the requests it can send to the server be
"send to all clients", which causes the server to forward the message to
all clients (or maybe to all clients except the initiator - your choice).

>"Receive-from" tasks include:
>- receiving replies from data requests to the server-stack
>- awaiting continously for server-mediated info about stack-events on host
>stacks
>
>The server-stack would either mediate or act as source to the above.
>  
>

I don't see anything in that description that prevents you from doing it
the following (relatively simple) way.

Overview:

The server is unique - must be findable from each client (DNS name if
you have the local network on DNS, or maybe a well-known IP address).
Each client opens a single TCP connection to the server; the TCP
connection remains open for the duration of the session.
That TCP session is used to carry all of
1. client requests
2. subsequent server responses
3. server initiated info
4. client responses to that.

As I said above, I'd make all communication go through the server -
helps for logging, testing, and general simplicity. I'd make it easy to
log every message to/from the server.

I'd make all messages consist of a "command tag" followed by any data
(so for instance, even a direct response to a request would have a tag
identifying that it is a response).

Reservation: depending on how many clients you expect to have, there may
be a problem with the simple scheme of a single, permanent TCP
connection. Simply keeping that connection open uses resources, both on
the network and more importantly within the server. Machines and OSes
have different limits on the number of simultaneous TCP connections they
can have. If it's a modern machine/OS, I *think* you should be OK with a
couple of hundred - but this definitely needs to be checked and/or tested.

Detail:

The server would do something like
(note - this is code from one of my stacks, but edited to remove all the
extraneous, confusing stuff, and some newly typed sections to restore
the minimal version of what I removed..... so there could be typos, or
simple errors - but the overall structure should be OK).

global gConnections

on startUp
accept connections on port "7654" with message "connectionMade"
put empty into gConnections
logWrite "Started on 7654"
end startUp

on connectionMade
put param(1) into theOtherOne
if the number of lines in gConnections >= 4 then -- set a suitable limit
for yourself
logWrite "Too many clients - rejected."
close socket theOtherOne
exit connectionMade
end if
put theOtherOne & cr after gConnections
read from socket theOtherOne until CR with message "readsome"
end connectionMade

on socketError s
put lineOffset(s, gConnections) into NConnection
if NConnection = 0 then
logWrite "Socket Error with unknown player."
else
logWrite "Socket" && s && "error:" && param(2)
delete line NConnection of gConnections
end if
end socketError

on socketClosed s
put lineOffset(s, gConnections) into NConnection
if NConnection = 0 then
logWrite "Attempt to close a socket that is not open."
else
logWrite "Socket" && s && "closed."
delete line NConnection of gConnections
end if
end socketClosed

on readsome
put param(1) into fromSocket
put lineOffset(fromSocket, gConnections) into NConnection
if NConnection = 0 then
logWrite "Input rejected - unknown player" & fromSocket
read from socket fromSocket until CR with message "readsome"
exit readsome
end if

-- so we are accepting the input - log it
logWrite "readsome" && NConnection && param(2)
-- note I should have handled multi-line input better for logging !!

put line 1 of param(2) into theInput
switch item 1 of theInput -- switch on the valid "commands"
case "setname"
-- an example of a command from a client that needs a response
-- store the user name in a the connections table
put TAB & item 2 of theInput after line nConnection of gConnections
-- and send him a welcome message
write "welcome," && item 2 of theInput & CR to socket fromSocket
break

case "shout"
-- an example of one client talking to EVERY other client
put item 2 of theInput into tMessage
broadcast tMessage
break

end switch
-- and prepare for more input ....
read from socket fromSocket until CR with message "readsome"
end readsome

on logWrite m -- should probably log to a file as well, not just to a field
put m & cr after field "outField"
end logWrite

on broadcast message
-- I use sequence numbers on all my messages. I deleted most of the code
that manages them,
-- but left in this mention of them, because I think they're a good idea.
add 1 to gSeqNumber
repeat for each line L in gConnections
put item 1 of L into tSocket
write gSeqNumber & COMMA & message & cr to socket tSocket
end repeat
end broadcast

on unicast pConnection, message
put item 1 of line pConnection of gConnection into tSocket
write gSeqNumber & COMMA & message & cr to socket tSocket
end unicast

The code for the client looks very similar, except
- they start out doing an open rather than an accept.
- all input is from the server, so no need for the connections table, or
checking which connection input is from

But generally, it's similar code - a single handler that gets input
after the connection is set up, and uses the "command" tag at the start
of the input to determine what to do.

Hope that helps a bit - if not, just holler.
-- Alex.


-- 
No virus found in this outgoing message.
Checked by AVG Anti-Virus.
Version: 7.0.298 / Virus Database: 265.6.7 - Release Date: 30/12/2004



More information about the use-livecode mailing list