[ Team LiB ] |
6.5 NSFileHandleNSFileHandle provides methods that let you read and write data from a file or communication channel asynchronously in the background. Chapter 2 discussed file access with NSFileHandle. This section describes NSFileHandle's asynchronous communications features and how they apply to networking. You can obtain a socket file descriptor from an instance of NSSocketPort by sending a socket message to the socket port object. With the socket descriptor, you are able to initialize an instance of NSFileHandle with the method initWithFileDescriptor:. The initWithFileDescriptor:closeOnDealloc: method is an extension of this method that specifies whether or not the file descriptor will close when the file handle object is deallocated. By default, the file handle object does not close the file descriptor and ownership of that descriptor remains with the object that created the file handle. To determine an NSFileHandle instance's file descriptor, invoke the method fileDescriptor. NSFileHandle provides the following three methods for performing asynchronous background communication:
NSFileHandle declares three additional methods that include a ForModes: argument:
The ForModes: argument specifies which run loop modes each method's notification may be posted in. This specification provides finer control over operation of the notification process. Example 6-8 shows how to use NSFileHandle to implement a simple server infrastructure. Example 6-8. Using NSFileHandle for server socket communication- (void)startServer { NSSocketPort *sockPort; sockPort = [[NSSocketPort alloc] initWithTCPPort:12345]; int socketFD = [sockPort socket]; NSFileHandle *listeningSocket; listeningSocket = [[NSFileHandle alloc] initWithFileDescriptor:socketFD]; NSNotificationCenter *nc; nc = [NSNotificationCenter defaultNotificationCenter]; [nc addObserver:self selector:@selector(spawnChildConnection:) name:NSFileHandleConnectionAcceptedNotification object:listeningSocket]; [listeningSocket acceptConnectionInBackgroundAndNotify]; } /* * This method is invoked in response to * NSFileHandleConnectionAcceptedNotification */ - (void)spawnChildConnection:(NSNotification *)note { NSFileHandle *connectedSocket = [[note userInfo] objectForKey:NSFileHandleNotificationFileHandleItem]; NSNotificationCenter *nc; nc = [NSNotificationCenter defaultNotificationCenter]; [nc addObserver:self selector:@selector(processClientData:) name:NSFileHandleReadCompletionNotification object:connectedSocket]; // Send a message to the client, acknowledging that the connection was accepted [connectedSocket writeData:ackData]; [connectedSocket readInBackgroundAndNotify]; } /* * This method is invoked in response to * NSFileHandleReadCompletionNotification */ - (void)processClientData:(NSNotification *)note { NSData *data = [[note userInfo] objectForKey:NSFileHandleNotificationDataItem]; // Do something here with your data // Tell file handle to continue waiting for data [[note object] readInBackgroundAndNotify]; } Example 6-9 shows a client infrastructure using NSFileHandle. Example 6-9. Using NSFileHandle on the client side- (void)startClient { NSSocketPort *sockPort; sockPort = [[NSSocketPort alloc] initRemoteWithTCPPort:12345 host:@"10.0.1.3"]; int sockFD = [sockPort socket]; NSFileHandle *clientSocket; clientSocket = [[NSFileHandle alloc] initWithFileDescriptor:sockFD]; NSNotificationCenter *nc; nc = [NSNotificationCenter defaultNotificationCenter]; [nc addObserver:self selector:@selector(processServerData:) name: NSFileHandleReadCompletionNotification object: clientSocket]; [clientSocket writeData:dataToWrite]; [clientSocket readInBackgroundAndNotify]; } /* * This method is invoked in response to * NSFileHandleReadCompletionNotification */ - (void) processServerData:(NSNotification *)note { NSData *data = [[note userInfo] objectForKey:NSFileHandleNotificationDataItem]; // Do something here with your data // Tell file handle to continue waiting for data [[note object] readInBackgroundAndNotify]; } |
[ Team LiB ] |