Updated: October 28, 2024 |
While the message-passing APIs transfer buffers of bytes without caring about the content, the client and server almost always care.
It's usually important to label the content, especially as most servers may support doing more than one operation (e.g., input and output). Data transmitted from a client to a server is generally identified with a message type, usually in the first few bytes in the message. The client includes the type in its messages, and the server examines the type to determine what action to take when it receives the message.
QNX Neutrino system messages (e.g., messages generated by standard C functions such as fork(), read(), or open()) start with a 16-bit unsigned integer (uint16_t) message type. You should use this message type to differentiate between your messages and system messages. System messages use values in the range from 0 through 511 (_IO_MAX, defined in <sys/iomsg.h>), so your messages should use types that are outside that range, that is, greater than 511. If different programs in your system define message types, you should use ranges that don't overlap.
A server should look at the message type in all incoming messages. If it recognizes the type, it should handle the message appropriately. If it doesn't recognize a message type or doesn't handle that type of message, it should reject the message by returning an error to the client with MsgError(). The expected errno value in this case is ENOSYS. It's also often a good idea to log a warning or error message in this case.
For example, your server might do this:
rcvid = MsgReceive(chid, &msg, sizeof(msg), NULL); switch( msg.type ) { case MY_MSG_1: handle_my_msg_1(); break(); case MY_MSG_2: handle_my_msg_2(); break; default: printf("Unexpected message of type %d from client rcvid: %x\n", msg.type, rcvid ); MsgError( rcvid, ENOSYS ); break; }