In gotAMessage(), you see the other half of the functionality, where we add a client to the list of clients waiting for data (if it's a MT_WAIT_DATA message), or we match up a client with the message that just arrived (if it's a MT_SEND_DATA message). Note that for simplicity we didn't add a queue of clients that are waiting to send data, but for which no receiver is yet available—that's a queue management issue left as an exercise for the reader!
/* * gotAMessage * * This routine is called whenever a message arrives. We * look at the type of message (either a "wait for data" * message, or a "here's some data" message), and act * accordingly. For simplicity, we'll assume that there is * never any data waiting. See the text for more discussion * about this. */ void gotAMessage (int rcvid, ClientMessageT *msg) { int i; // determine the kind of message that it is switch (msg -> messageType) { // client wants to wait for data case MT_WAIT_DATA: // see if we can find a blank spot in the client table for (i = 0; i < MAX_CLIENT; i++) { if (!clients [i].in_use) { // found one -- mark as in use, save rcvid, set timeout clients [i].in_use = 1; clients [i].rcvid = rcvid; clients [i].timeout = 5; return; } } fprintf (stderr, "Table full, message from rcvid %d ignored, " "client blocked\n", rcvid); break; // client with data case MT_SEND_DATA: // see if we can find another client to reply to with // this client's data for (i = 0; i < MAX_CLIENT; i++) { if (clients [i].in_use) { // found one -- reuse the incoming message // as an outgoing message msg -> messageType = MT_OK; // reply to BOTH CLIENTS! MsgReply (clients [i].rcvid, EOK, msg, sizeof (*msg)); MsgReply (rcvid, EOK, msg, sizeof (*msg)); clients [i].in_use = 0; return; } } fprintf (stderr, "Table empty, message from rcvid %d ignored, " "client blocked\n", rcvid); break; } }