bw logo

Chapter 33. Non-Blocking Socket I/O Using Mercury

TCP/IP is commonly used to communicate with third party products, like billing systems, for example. However, care must be taken to avoid blocking the main thread of the program.

One option is to spawn separate threads to handle the I/O, but the recommended option is to use non-blocking I/O. Mercury uses non-blocking I/O by default, and provides callbacks on I/O events to enable the program to wait for something without blocking the main thread.

33.1. Getting Callbacks From Mercury::EventDispatcher

The Mercury::EventDispatcher class contains the main loop of almost all the server executables: Mercury::EventDispatcher::processContinuously().

This function effectively time slices the main thread by waiting for events to happen on sockets, and then calling handlers to process those events. It is vital that all event handler does not to block or take a significant amount of processing time, otherwise the others will be starved.

The following Mercury::EventDispatcher methods allow event handlers to be registered:

  • registerFileDescriptor

    bool registerFileDescriptor( int fd, InputNotificationHandler * handler );

  • deregisterFileDescriptor

    bool deregisterFileDescriptor( int fd );

  • registerWriteFileDescriptor

    bool registerWriteFileDescriptor( int fd, InputNotificationHandler * handler );

  • deregisterWriteFileDescriptor

    bool deregisterWriteFileDescriptor( int fd );

The handleInputNotification method of an InputNotificationHandler object registered via registerFileDescriptor will be called when the specified file descriptor (usually a socket) has data available for reading.

The handleInputNotification method of an InputNotificationHandler object registered via registerWriteFileDescriptor will be called when the specified file descriptor (usually a socket) is ready for writing. This is useful when writing a large amount of data. A non-blocking write operation will only write an amount of data equal to, or less than, its internal buffers can hold. Then the program must wait until the socket is again ready to be written to. Waiting for a socket to become writable is also useful during the TCP connection process, as the socket will not be ready for writing until the connection is fully established.

All registered handlers must be de-registered using the corresponding function. They are not automatically de-registered when the file descriptor is closed.

For more details, see the example file bigworld/src/server/baseapp/eg_tcpecho.cpp.