But RexxSock is not limited to this design. It is entirely possible to have a server script that allows many (ie, upto 64) clients to simultaneously connect. The drawback is that, unlike the previous server example, it becomes a bit more complicated to manage several clients simultaneously. So, if your server need deal with only one client at a time, then the preceding simple server example is the easiest way to go.
A server socket can be like a telephone that has "call waiting" and "caller ID" service.
It is possible to allow several client computers to connect to that same server socket (ie, port) simultaneously. RexxSock will notify you as each call comes in (ie, call waiting). Your script tells RexxSock how many clients at most you wish to allow to connect simultaneously. So, you can set a limit on your "call waiting" service. To tell RexxSock that you wish to let more than one client connect simultaneously, you pass SockSocket a number that tells RexxSock how many clients maximum can connect simultaneously. For example, here we specify that we allow upto 25 clients to connect simultaneously:
/* Get a server socket, and let 25 clients simultaneously connect to it. */ server = SockSocket(, , , 'server.!', 25, 0)As each client connects, SockSelect will notify you that a client is trying to connect. You can call SockAccept as many times as desired, to accept as many clients' calls as you wish. Each call to SockAccept will accept one client's connection, and return a unique socket for each client. So, if you accept many client connections at once, then your script will have to keep track of several sockets, and pass the appropriate socket to SockSend and SockRecv to communicate with the desired client. The following example is a simple server script. It creates a server socket that listens for connections on port number 20248. It allows only one client at a time to connect. When a client connects, the server script sends the string Hello world! to the client, and then waits for the client to send back the string Hi!. Then, the server hangs up.
/* Initialization. */ OPTIONS "C_CALL" LIBRARY rexxsock /* Set the desired port number we want for our socket, and * indicate what our IP address is. We must store this information * in a stem variable, and then we will pass the name of this stem * variable to SockSocket. SockSocket will retrieve this information * and create a server socket. We can use any stem variable name we * wish. Here we use "server.!", but we must set two tails, named * port and addr. We have decided to use a port number of 20248. As * for the IP address, if we set the port tail to the string * "INADDR_ANY", then SockSocket will automatically lookup this * computer's primary IP address for us. */ server.!addr = 'INADDR_ANY' /* Let RexxSock look up this computer's IP address */ server.!port = 20248 /* This is the port we use to communicate. The client must use the same port # */ /* Get a server socket using the above port/address. Set it into * "listening for connections" mode, and allow only 1 client to wait * for us to SockAccept it. If more than one client tries to connect * simultaneously, RexxSock will automatically reject all but the * first client. */ server = SockSocket(, , , 'server.!', 1) SAY 'Server socket created and waiting for a client to connect...' /* SockAccept will wait for and accept an incoming client connection * and return that client's socket. Here we store that socket in * a variable named "client". We also pass the name of a stem * variable to SockAccept, and SockAccept fills in that stem's * addr with the IP address of the client we connect to. You * can use any stem variable name you desire. Here we use "client.!". */ client = SockAccept(server, 'client.!') /* We got a client connected. Display its IP address. */ SAY 'Client connected from address' client.!addr /* Send "Hello World!" to that client. Note that we * pass the client socket to SockSend (not our server socket). */ SockSend(client, 'Hello world!') /* Wait for the client to reply with its "Hi!". We omit the * timeout arg, so we wait forever. If we pass the timeout arg, * SockSelect will raise the USER condition for a time out. We * need to first fill in a stem variable where the tail 0 tells how * many sockets to wait for (ie, 1 here), and then the remaining * tails are those sockets. We must pass that stem name as the * first arg to SockSelect. Here, we use a stem variable named * "reads.", but you could use any name you like. Note that we * store the client socket in it. */ reads.0 = 1 reads.1 = client timedout = SockSelect('reads.') /* Read upto the next 250 bytes of data from the client. SockRecv * returns the number of bytes actually read, and stuffs those bytes * into some variable of our choice. Here, we use a variable named * "chunk", and pass that name to SockRecv. SockRecv will raise * USER condition if the socket has been shutdown/closed by the * client, or if some other error occurs. */ bytes = SockRecv(client, 'chunk', 250) /* Display what we received. */ SAY chunk /* Close the socket. RexxSock will tell the client we're closing * the connection. */ SockClose(socket, 1) SAY 'Socket closed' /* At this point we could loop around to SockAccept to wait for * another client to connect, instead of terminating. */ RETURN /* ========================================================== * We told RexxSock to raise the USER 10 condition if there is * ever any error (other than a SYNTAX error). We CATCH USER * 10 here, so REXX will jump here if it is raised. So, if * we're here, then some RexxSock function has had an error. * * CONDITION('D') reports the name of the RexxSock function that * had the error. SIGL is the line number in our script where * we had the error. The variable named "SockErrNo" is set to an * RexxSock Error name such as "EINPROGRESS" or "ENETDOWN" etc. * We can pass this variable to the RexxSock function SockErrMsg * to get an appropriate error message or call SockPSock_Errno * to display a message box. */ CATCH USER 10 SockPSock_Errno() /* If you wish your server script to continue executing, instead * of aborting, then here you would examine "SockErrNo", and * do some handling based upon it. Then, you would SIGNAL * back to some safe place in the script, such as going * back to SockSelect() to wait for something more to * happen. */ RETURN CATCH SYNTAX CONDITION('M') RETURN