We will, however, pause here to give a brief high-level overview of MUSCLE's functionality.
MUSCLE's basic unit of communication is the Message object. A MUSCLE Message is a dictionary-style object very similar to BeOS's BMessage class (on which it was originally based). When using MUSCLE, you don't send streams or packets of bytes across the network; you send (and receive) Messages. Each Message contains a 32-bit-integer 'what' code (which you may set to any value you wish), and an arbitrary number of uniquely named data fields. Each data field may contain one or more values of the same type. Here is an example of what a Message might look like:
Message what=0x1234 Field name="groceries to buy" type=B_STRING_TYPE Item 0. value="bread" Item 1. value="milk" Item 2. value="eggs" Field name="prices to pay" type=B_FLOAT_TYPE Item 0. value=2.99f Item 1. value=0.99f Field name="PIN Number" type=B_INT32_TYPE Item 0. value=8288945
As you can see, each field must have a unique name, but can have any number of values in it. Possible field data types include integers (8, 16, 32, and 64-bit), floats, doubles, strings, points, rectangles, other Messages(!), and raw byte arrays. Because type information is stored with the Message, MUSCLE is able to handle all data translation and transmission issues automatically. Also, because Messages can be nested inside other Messages, and because a Message knows how to flatten itself into a standardized, architecture-neutral flattened byte sequence, Messages provide a convenient way to store hierarchical data to disk. Lastly, because you can add new fields to a Message without disturbing the old ones, Messages make it trivial to maintain data-compatibility with old code -- the old code will safely ignore the new data fields, and new code can easily detect when the new data fields are missing and supply appropriate defaults.
MUSCLE network communication is asynchronous, and MUSCLE provides both single-threaded APIs and multi-threaded APIs to queue up incoming and outgoing messages and feed them out across the network (or in to the local app) at the fastest possible speed, without ever blocking the execution of the main program's event loop. This is important, because it means that slow network connections will never cause the client's GUI to "freeze up" -- and similarly, a single poor-quality client connection will not keep a MUSCLE server from servicing its other clients promptly.
The MUSCLE server, while included in the standard MUSCLE distribution, is actually not a required component. It is quite possible and even somewhat common to create a MUSCLE application that doesn't make use of the MUSCLE server, and uses only direct client-to-client connections. However, as we will see in the next section, using a central server can provide some distinct advantages for your app.
- "Foxes, Rabbits, and Carrots"
- "The Game and How to Play it"
- "A Brief Review of the MUSCLE Networking Layer"
- "muscled, The basic MUSCLE server"
- "Customizing the MUSCLE server"
- "How to Set up the Custom Server Logic"
- "The FRCPlayerSession Class"
- "The FRCGameStateSession class"
- "Overview of the FRC server"
- "The FoxRabbitCarrot Client Program"
- "How the Client Handles Database Update Messages"
- "MUSCLE gaming Performance Issues"