Socket Flags

team bbl


The behaviors of a socket when using the socket classes can be quite different depending on which socket flags are set. The socket flags and their meanings are described in Table 18-3 and in more detail below.

Table 18-3. Socket Flags

wxSOCKET_NONE

Normal functionality (the behavior of the underlying send and recv functions).

wxSOCKET_NOWAIT

Read or write as much data as possible and return immediately.

wxSOCKET_WAITALL

Wait for all required data to be read or written unless an error occurs.

wxSOCKET_BLOCK

Block the GUI while reading or writing data.


If no flag is specified (the same as wxSOCKET_NONE), I/O calls will return after some data has been read or written, even when the transfer might not be complete. This is the same as issuing exactly one blocking low-level call to recv or send. Note that blocking here refers to when the function returns, not whether the GUI blocks during this time.

If wxSOCKET_NOWAIT is specified, I/O calls will return immediately. Read operations will retrieve only the available data, and write operations will write as much data as possible, depending on how much space is available in the output buffer. This is the same as issuing exactly one non-blocking low-level call to recv or send. Note that non-blocking here refers to when the function returns, not whether the GUI blocks during this time.

If wxSOCKET_WAITALL is specified, I/O calls won't return until all the data has been read or written (or until an error occurs), blocking if necessary and issuing several low-level calls if needed. This is the same as having a loop that makes as many blocking low-level calls to recv or send as needed to transfer all the data. Again, blocking here refers to when the function returns, not whether the GUI blocks during this time. Note that ReadMsg and WriteMsg will implicitly use wxSOCKET_WAITALL and ignore wxSOCKET_NONE and wxSOCKET_NOWAIT.

The wxSOCKET_BLOCK flag controls whether the GUI blocks during I/O operations. If this flag is specified, the socket will not yield during I/O calls, so the GUI will remain blocked until the operation completes. If it is not used, then the application must take extra care to avoid unwanted re-entrance.

To summarize:

  • wxSOCKET_NONE will try to read at least some data, no matter how much.

  • wxSOCKET_NOWAIT will always return immediately, even if it cannot read or write any data.

  • wxSOCKET_WAITALL will only return when it has read or written all the data.

  • wxSOCKET_BLOCK has nothing to do with the previous flags; it controls whether the GUI blocks during socket operations.

Blocking and Non-Blocking Sockets in wxWidgets

The term blocking has a dual meaning in wxWidgets. In standard socket programming, blocking means that the current thread hangs (blocks) on the recv function until a timeout occurs or the full amount of data is read. If that thread happens to be the main thread, then the GUI blocks as well.

Under wxWidgets, however, blocking can refer to two different types of blocking: socket blocking and GUI blocking. The purpose of the wxSOCKET_BLOCK flag is to specify whether the GUI will block if the socket call blocks. How is it possible that the socket call can block but the GUI does not? This is possible because events can continue to be processed through calls to wxYield while the socket operation is incomplete. wxYield will process pending events in the event queue, including GUI events. As long as the socket operation has not completed, your code is blocked on the socket function, but events are continuously processed.

To the wxWidgets newcomer, this appears to be a panacea for socket applications. The first time you work with sockets on wxWidgets, it's easy to believe that you will never need another thread to process sockets. You might think that you could simply use socket events and set all sockets to use wxSOCKET_WAITALL without wxSOCKET_BLOCK. Unfortunately, attempting this can have a deadly side effect, and it produces a warning message that can be a source of confusion.

Consider the case of a server with two active connections, each connection with wxSOCKET_WAITALL as the active socket flag. Furthermore, imagine that a large amount of data is being received over a slow connection. Socket 1 has no data in the read buffer, so it calls wxYield. There is still a pending event on Socket 2, so wxWidgets attempts to process that event. However, that event cannot complete, and it also calls wxYield. This will cause the infamous "wxYield called recursively" message to appear. Eventually the stack would fill up with recursive calls to wxYield as long as all the data has not yet arrived and the call stack cannot unwind. Many users immediately assume that this error message indicates a flaw in wxWidgets, when the truth is that it represents a problem in the application code. Simply stated, applications should be programmed so that this situation does not occur; the error is present to reveal a problem in the application code so that it can be fixed.

That aside, there is still another side effect of allowing socket calls to block without blocking the GUIyour application will consume as much CPU time as has been allocated to it. The reason for this is that events must be immediately processed for the application to remain responsive, but the socket must also be monitored for data so that it can return immediately when data is available. The only way to do this is in a busy loop, constantly calling a non-blocking select on the socked followed by a call to wxYield.

The Impossible Socket Combination

Just to reiterate, do not be fooled into thinking that wxWidgets has created miraculous socket processing. You cannot simultaneously have all of the following, no matter how much it appears at first glance that you can:

  • wxSOCKET_WAITALL

  • No GUI blocking

  • Less than 100% CPU usage

  • A single thread

You can specify wxSOCKET_WAITALL without blocking the GUI, but it will cause 100% CPU usage. You can use wxSOCKET_WAITALL and have 0% CPU usage if you also block the GUI with wxSOCKET_BLOCK. You can use wxSOCKET_WAITALL without blocking the GUI or using 100% CPU if you use secondary threads. You can use sockets in a single thread without 100% CPU usage or blocking the GUI, but you have to use wxSOCKET_NOWAIT. You can have any three of these things simultaneously, just not all four.

How Flags Affect Socket Behavior

Given that wxSOCKET_NONE, wxSOCKET_NOWAIT, and wxSOCKET_WAITALL are mutually exclusive, and that wxSOCKET_BLOCK makes no sense combined with wxSOCKET_ NOWAIT (if the function returns immediately, how can the GUI ever block?), there are five meaningful flag combinations:

  • wxSOCKET_NONE | wxSOCKET_BLOCK: Behaves like standard blocking socket calls (calls to recv and send).

  • wxSOCKET_NOWAIT: Behaves like standard non-blocking socket calls.

  • wxSOCKET_WAITALL | wxSOCKET_BLOCK: Behaves like standard blocking socket calls, except that the underlying send or recv will be called repeatedly until all data is sent or received.

  • wxSOCKET_NONE: Behaves like standard socket calls except that the GUI will not block because of continuous calls to wxYield while the socket operation is incomplete (for example, not all data has been read).

  • wxSOCKET_WAITALL: Behaves like wxSOCKET_WAITALL | wxSOCKET_BLOCK except that the GUI will not block.

Only the last two can lead to the recursive wxYield problem, although they are also the most useful when using socket events in the primary thread (because they are socket blocking but not GUI blocking). Extreme caution should be exercised while using these two options. Although they are very powerful, they are also the source of many problems and frustrations because they are so frequently misunderstood.

Using wxSocket as a Standard Socket

Using sockets with wxSOCKET_NONE | wxSOCKET_BLOCK or wxSOCKET_NOWAIT in wxWidgets is no different from using C sockets, except that you use wxSocket methods instead of C functions. The wxSocket class still provides many advantages over using the C API directly, including an object-oriented interface, hiding a lot of the bulky platform-dependent initialization code, providing consistent behavior from one platform to the next (especially with regards to error codes, which differ widely from platform to platform), and some higher-level functions like WriteMsg and ReadMsg. As we'll see next, using wxSocket also lets us take advantage of socket streams.

    team bbl



    Cross-Platform GUI Programming with wxWidgets
    Cross-Platform GUI Programming with wxWidgets
    ISBN: 0131473816
    EAN: 2147483647
    Year: 2005
    Pages: 262

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net