Multi-client servers have two distinct parts. One part of the program listens for new incoming connections while the other handles currently active connections and closes any recently inactive connections. Because both parts of the program must run simultaneously, you must set up a form of communication between the VIs beyond standard wiring. You can accomplish this with local or global variables, but other data structures such as queues are more manageable.
During standard execution, the listening portion of the program receives and validates a new connection. Upon receiving the connection, the "listener" informs the talking part of the program via the queue. At the same time, the "talker" maintains a list of all of the active connections that it must handle on each iteration of its execution loop. When the listener informs the talker of a new connection, the talker adds this new connection to the list. When a client disconnects (or is forcibly disconnected), the talker closes this connection and removes it from the list of clients with which it must communicate.
The following figure shows the "listener" loop. This loop checks for new connections. The timeout value is important, since listen will block the thread while it is waiting. Timeout is 10ms in this example. Since the listen attempt may timeout (error code 56), you must check for that condition.
The second case of the inner case structure handles the timeout case by doing nothing. If, however, a valid connection is detected, the VI adds it to the Connections queue inside the inner case structure. Note the use of the Flatten to String function to add the non-string connection ID to the queue. Once the VI adds the connection or the listen times out, the loop completes and restarts with the TCP Listen VI.
In the "talking" portion of the example, you must perform two tasks:
- Check the queue and retrieve any new connections that have been made since the last check. Checking the queue status determines how many new elements are in the queue. This VI unflattens all the new connection IDs inside the "get new connections" loop. The VI then builds an array of the new connections using autoindexing and adds this new array to the array of existing connections stored in the shift register.
- Use the second For loop to handle each individual connection. The inner For loop builds a new connections array, leaving out any connections that closed on this iteration of connection handling. Notice that the True case passes through the For loop connection array, while the False case adds the current connection to the array.
You should also consider using Event Structures for a more efficient architecture with multi-client servers. This example was created before the Event Structure was introduced in LabVIEW 6.1.