Nicolas Cueto wrote: (B (B> To enable my (sometimes unduly hesitant!) (B>language-learners to interact aurally and visually over the school LAN, I (B>want to create a client-stack capable of sending to and receiving from a (B>likewise cofigure server-stack both data and stack-events -- and all (B>happening live, sometimes simultaneously (e.g., within one card's script), (B>and with as few ports/handlers as possible! (B> (B>"Send-to" taks for the client-stack include: (B>- logging-in so that everyone knows who's on-line (B>- making requests for various types of data (B>- broadcasting local stack events to all or some host stacks (B> (B> (BIf at all possible, I'd make each client talk ONLY to the server. Make (Bone of the requests it can send to the server be (B"send to all clients", which causes the server to forward the message to (Ball clients (or maybe to all clients except the initiator - your choice). (B (B>"Receive-from" tasks include: (B>- receiving replies from data requests to the server-stack (B>- awaiting continously for server-mediated info about stack-events on host (B>stacks (B> (B>The server-stack would either mediate or act as source to the above. (B> (B> (B (BI don't see anything in that description that prevents you from doing it (Bthe following (relatively simple) way. (B (BOverview: (B (BThe server is unique - must be findable from each client (DNS name if (Byou have the local network on DNS, or maybe a well-known IP address). (BEach client opens a single TCP connection to the server; the TCP (Bconnection remains open for the duration of the session. (BThat TCP session is used to carry all of (B1. client requests (B2. subsequent server responses (B3. server initiated info (B4. client responses to that. (B (BAs I said above, I'd make all communication go through the server - (Bhelps for logging, testing, and general simplicity. I'd make it easy to (Blog every message to/from the server. (B (BI'd make all messages consist of a "command tag" followed by any data (B(so for instance, even a direct response to a request would have a tag (Bidentifying that it is a response). (B (BReservation: depending on how many clients you expect to have, there may (Bbe a problem with the simple scheme of a single, permanent TCP (Bconnection. Simply keeping that connection open uses resources, both on (Bthe network and more importantly within the server. Machines and OSes (Bhave different limits on the number of simultaneous TCP connections they (Bcan have. If it's a modern machine/OS, I *think* you should be OK with a (Bcouple of hundred - but this definitely needs to be checked and/or tested. (B (BDetail: (B (BThe server would do something like (B(note - this is code from one of my stacks, but edited to remove all the (Bextraneous, confusing stuff, and some newly typed sections to restore (Bthe minimal version of what I removed..... so there could be typos, or (Bsimple errors - but the overall structure should be OK). (B (Bglobal gConnections (B (Bon startUp (Baccept connections on port "7654" with message "connectionMade" (Bput empty into gConnections (BlogWrite "Started on 7654" (Bend startUp (B (Bon connectionMade (Bput param(1) into theOtherOne (Bif the number of lines in gConnections >= 4 then -- set a suitable limit (Bfor yourself (BlogWrite "Too many clients - rejected." (Bclose socket theOtherOne (Bexit connectionMade (Bend if (Bput theOtherOne & cr after gConnections (Bread from socket theOtherOne until CR with message "readsome" (Bend connectionMade (B (Bon socketError s (Bput lineOffset(s, gConnections) into NConnection (Bif NConnection = 0 then (BlogWrite "Socket Error with unknown player." (Belse (BlogWrite "Socket" && s && "error:" && param(2) (Bdelete line NConnection of gConnections (Bend if (Bend socketError (B (Bon socketClosed s (Bput lineOffset(s, gConnections) into NConnection (Bif NConnection = 0 then (BlogWrite "Attempt to close a socket that is not open." (Belse (BlogWrite "Socket" && s && "closed." (Bdelete line NConnection of gConnections (Bend if (Bend socketClosed (B (Bon readsome (Bput param(1) into fromSocket (Bput lineOffset(fromSocket, gConnections) into NConnection (Bif NConnection = 0 then (BlogWrite "Input rejected - unknown player" & fromSocket (Bread from socket fromSocket until CR with message "readsome" (Bexit readsome (Bend if (B (B-- so we are accepting the input - log it (BlogWrite "readsome" && NConnection && param(2) (B-- note I should have handled multi-line input better for logging !! (B (Bput line 1 of param(2) into theInput (Bswitch item 1 of theInput -- switch on the valid "commands" (Bcase "setname" (B-- an example of a command from a client that needs a response (B-- store the user name in a the connections table (Bput TAB & item 2 of theInput after line nConnection of gConnections (B-- and send him a welcome message (Bwrite "welcome," && item 2 of theInput & CR to socket fromSocket (Bbreak (B (Bcase "shout" (B-- an example of one client talking to EVERY other client (Bput item 2 of theInput into tMessage (Bbroadcast tMessage (Bbreak (B (Bend switch (B-- and prepare for more input .... (Bread from socket fromSocket until CR with message "readsome" (Bend readsome (B (Bon logWrite m -- should probably log to a file as well, not just to a field (Bput m & cr after field "outField" (Bend logWrite (B (Bon broadcast message (B-- I use sequence numbers on all my messages. I deleted most of the code (Bthat manages them, (B-- but left in this mention of them, because I think they're a good idea. (Badd 1 to gSeqNumber (Brepeat for each line L in gConnections (Bput item 1 of L into tSocket (Bwrite gSeqNumber & COMMA & message & cr to socket tSocket (Bend repeat (Bend broadcast (B (Bon unicast pConnection, message (Bput item 1 of line pConnection of gConnection into tSocket (Bwrite gSeqNumber & COMMA & message & cr to socket tSocket (Bend unicast (B (BThe code for the client looks very similar, except (B- they start out doing an open rather than an accept. (B- all input is from the server, so no need for the connections table, or (Bchecking which connection input is from (B (BBut generally, it's similar code - a single handler that gets input (Bafter the connection is set up, and uses the "command" tag at the start (Bof the input to determine what to do. (B (BHope that helps a bit - if not, just holler. (B-- Alex. (B (B (B-- (BNo virus found in this outgoing message. (BChecked by AVG Anti-Virus. (BVersion: 7.0.298 / Virus Database: 265.6.7 - Release Date: 30/12/2004 (B (B_______________________________________________ (Buse-revolution mailing list ([email protected] (Bhttp://lists.runrev.com/mailman/listinfo/use-revolution
