9.14. Distributed ObjectsThe Objective-C runtime environment provides an IPC mechanism called Distributed Objects that allows one application to call a remote object, which could be in another application, in a different thread in the same application, or even in an application running on another computer. In other words, Distributed Objects supports intramachine or intermachine remote messaging. Distributed Objects makes it rather simple to make a remote object locally available, although the usual distributed computing caveats related to latency, performance, and reliability still apply. Let us look at a client-server system implemented using Distributed Objects. In our system, the server object (DOServer) will implement the ClientProtocol Objective-C protocol, whose methods will be called by the client as follows.
The client object (DOClient) will implement a single method as part of the ServerProtocol Objective-C protocol. This methodwhoAreYouwill be called from the server's implementation of the helloFromClient method. This is to demonstrate that both the client and the server can remotely call each other's methods.
The server will create an instance of the NSConnection class for receiving client requests on a well-known (to our client) TCP port. It will then call the setRootObject method of NSConnection to attach the server object to the connection. Thereafter, the object will be available to other processes through the connection. This is referred to as vending an object.
Note that although we use sockets for communication, Distributed Objects can use other communication mechanisms too, such as Mach ports. Moreover, remote messaging can be synchronous, blocking the sender until a reply is received, or it can be asynchronous, in which case no reply is desired. The client will begin by establishing a connection to the serveragain, an instance of the NSConnection class. It will then call the rootProxy method of NSConnection to retrieve the proxy for the root object of the server end of the connection. This way, the client will have a proxy objectan instance of the NSDistantObject classin its address space representing the vended object in the server's address space. Thereafter, the client can send messages to the proxy object with reasonable transparencyas if it were the real object. Figure 947 shows the working of our client and server. Figure 947. Communication in a Distributed Objects client-server systemIn Objective-C, a local object's methods are invoked by sending the appropriate messages to the object. In Figure 947, when a method of the remote object is invoked, the Objective-C message goes to the NSDistantObject instance, which renders the message static by turning it into an instance of the NSInvocation class. The latter is a container for carrying all constituents of a messagesuch as target, selector, arguments, return value, and data types of the arguments and the return value. The NSConnection instance encodes the NSInvocation object into a low-level, platform-independent formNSPortMessagethat contains a local port, a remote port, a message ID, and an array of encoded data components. The encoded data is eventually transmitted across the connection. The reverse process occurs on the server: When the NSPortMessage is received by the server, it is decoded and given to NSConnection as an NSPortMessage. NSConnection converts the NSPortMessage to an NSInvocation and finally sends the corresponding message, along with arguments, to the target (the vended object). This is referred to as dispatching theNSInvocation. Our implementation of the client-server system consists of a common header file (do_common.h, shown in Figure 948), the server source (do_server.m, shown in Figure 949), and the client source (do_client.m, shown in Figure 950). Figure 948. Common header file for the Distributed Objects client-server example
Figure 949. Server source for the Distributed Objects client-server example
Figure 950. Client source for the Distributed Objects client-server example
Let us now test the Distributed Objects client-server system. $ gcc -Wall -o do_server do_server.m -framework Foundation $ gcc -Wall -o do_client do_client.m -framework Foundation $ ./do_server # another shell prompt $ ./do_client ... do_client[4741] 13.000000 ... do_server[4740] I am a DO client. Note that we use the NS_DURING, NS_HANDLER, and NS_ENDHANDLER macros in our client and server implementations. These demarcate an exception-handling domain and a local exception handler. Specifically, if an exception is raised in the section of code between NS_DURING and NS_HANDLER, the section of code between NS_HANDLER and NS_ENDHANDLER is given a chance to handle the exception. Figure 951 shows a code excerpt with the expanded forms of these macros. Figure 951. Exception-handling macros in the Foundation framework
|