A dual-channel communication system: a general-purpose and an immediate-response socket

Top  Previous  Next

Caution: technical information!

 

The event-driven system and the separation of client and server is an enormously powerful technique, but it involves one area of complexity. That concerns queries that require an immediate and specific response.

 

For example, if (as the client) you wish to know whether an infra-red nosepoke detector is on or off, you may ask the server. But you do not wish to pause while waiting for the answer (you wish to know the device's state now, and you do not want to hold up processing of other ongoing events).

 

Imagine that as you begin to ask this question of the server, the server has detected a lever-press for which you have requested notification. It sends the event message at the same instant you send the query about the nosepoke detector. We have a dilemma: you don't want a lever-press event in response to your nosepoke query, you don't want to process the lever-press event until you know the nosepoke detector status (let's say), and you don't want to have your 'nosepoke query' routine handle lever-press events itself (that would be needlessly difficult to program in a task of realistic complexity!).

 

This is a problem whenever we have one channel of communication and when the server may send event messages at unpredictable times. If the 'client' and 'server' were the same program (as in every other operant control system currently on the market, to my knowledge) it would be easy to organize the program so the nosepoke detector request could take priority and hold up processing of the lever-press event. But this would defeat the many advantages of client–server separation. So we must get around the problem.

 

The way I have chosen to do this is to use two communication channels between the client and the server. Now, you don't have to use two channels, but whenever this problem crops up it is a good solution (and believe me, it crops up all the time). In the network system we are using, communication channels are known as sockets, so this is a two-socket system.

 

One socket is called the main socket. You may send commands to the server through this socket, and the server will send all of its event notification messages (and other unsolicited information) down this socket. The other is a called the immediate socket. The server guarantees two things about communication down the immediate socket:

 

1.The server will send nothing to you through this socket, except in direct response to commands that you send to it through this socket.
2.Every command you send will be responded to immediately, and that response will comprise a single message, or one line of text.

 

As the client, you should implement the immediate socket as a 'blocking' socket (I apologize for the networking terminology; this means that when you say to the socket 'give me the server's reply', it waits for that reply if necessary and then returns it to you; the socket never says 'sorry, no information has come from the server yet').

 

Don't worry, you shouldn't have to work with this system directly – all the technical detail is implemented for you in the SDK.

 

You cannot connect more than one immediate socket to a given client.

 

Clients can issue commands on either the main or immediate socket. If the comand is issued through the immediate socket, as most will be, the Server will send a reply (an Info: message about success, or an Error: or SyntaxError: message about failure) to the main socket only. The possible replies are shown in the reference above. Responses down the main socket give a good deal of ancillary information and are useful to the watching human.

 

If a command is sent to the immediate socket, then a single reply will be sent to the immediate socket. In general, responses to commands down the immediate socket are much simpler and more sharply defined, and consequently easier to deal with for the client task. If the command fails, the server will also send the relevant SyntaxError: or Error: report to the main socket, in addition to the message on the immediate socket. If the command succeeds, no Info: message will usually be sent to the main socket.

 

Note once more that every message coming from the server will be terminated by a linefeed (LF, ASCII 10, \n), and that client messages should be terminated by a linefeed, CR or semicolon.