使用socket套接字源码(Connection源码)

来源:互联网 发布:手机版晒密软件 编辑:程序博客网 时间:2024/05/17 04:34

 

//Connection.h
#import <Foundation/Foundation.h>#import "ConnectionDelegate.h"@interface Connection : NSObject {    id<ConnectionDelegate>  delegate;        // Connection info: host address and port    NSString *              host;    NSInteger               port;    NSString *              peerhost;    NSInteger               peerport;        // Connection info: native socket handle    CFSocketNativeHandle    connectedSocketHandle;                // Read stream    CFReadStreamRef         readStream;    BOOL                    readStreamOpen;    NSMutableData *         incomingDataBuffer;    int                    packetBodySize;    // Write stream    CFWriteStreamRef        writeStream;    BOOL                    writeStreamOpen;    NSMutableData *         outgoingDataBuffer;}@property(nonatomic, retain) id<ConnectionDelegate> delegate;@property(nonatomic, retain) NSString * host;@property(nonatomic, assign) NSInteger port;@property(nonatomic, retain) NSString * peerhost;@property(nonatomic, assign) NSInteger peerport;// Initialize using a native socket handle, assuming connection is open- (id) initWithNativeSocketHandle:(CFSocketNativeHandle)nativeSocketHandle;// Connect using whatever connection info that was passed during initialization- (BOOL) connect;// Close connection- (void) close;// Send network message- (void) sendNetworkPacket:(NSDictionary *)packet;@end


 

//Connection.m文件//#import "Connection.h"#include <sys/socket.h>#include <netinet/in.h>#include <unistd.h>#include <arpa/inet.h>// Declare C callback functionsvoid readStreamEventHandler(CFReadStreamRef stream, CFStreamEventType eventType, void *info);void writeStreamEventHandler(CFWriteStreamRef stream, CFStreamEventType eventType, void *info);#pragma mark - Connection - Private properties and methods@interface Connection ()// Properties@property(nonatomic, assign) CFSocketNativeHandle connectedSocketHandle;// Initialize- (void) clean;// Further setup streams created by one of the 'init' methods- (BOOL) setupSocketStreams;// Stream event handlers- (void) readStreamHandleEvent:(CFStreamEventType)event;- (void) writeStreamHandleEvent:(CFStreamEventType)event;// Read all available bytes from the read stream into buffer and try to extract packets- (void) readFromStreamIntoIncomingBuffer;// Write whatever data we have in the buffer, as much as stream can handle- (void) writeOutgoingBufferToStream;@end@implementation Connection@synthesize delegate;@synthesize host, port, peerhost,peerport;@synthesize connectedSocketHandle;#pragma mark - Lifecycle// Initialize, empty- (void) clean{      readStream = nil;    readStreamOpen = NO;        writeStream = nil;    writeStreamOpen = NO;        incomingDataBuffer = nil;    outgoingDataBuffer = nil;        self.host = nil;    connectedSocketHandle = -1;    packetBodySize = -1;}// Initialize using a native socket handle, assuming connection is open- (id) initWithNativeSocketHandle:(CFSocketNativeHandle)nativeSocketHandle{        [self clean];        self.connectedSocketHandle = nativeSocketHandle;        struct sockaddr_in peeraddr;    struct sockaddr_in addr;    socklen_t addrLen = sizeof(peeraddr);        // get loacl address    getsockname(nativeSocketHandle, (struct sockaddr *)&addr, &addrLen);    self.host = [NSString stringWithCString:inet_ntoa(addr.sin_addr) encoding:NSUTF8StringEncoding];    self.port = ntohs(addr.sin_port);            // get peer address    getpeername(nativeSocketHandle, (struct sockaddr *)&peeraddr, &addrLen);    self.peerhost = [NSString stringWithCString:inet_ntoa(peeraddr.sin_addr) encoding:NSUTF8StringEncoding];    self.peerport = ntohs(peeraddr.sin_port);            return self;}// cleanup- (void) dealloc{        self.host = nil;    self.delegate = nil;        [super dealloc];}#pragma mark - Network// Connect using whatever connection info that was passed during initialization- (BOOL) connect{    if ( self.connectedSocketHandle != -1 ) {        // Bind read/write streams to a socket represented by a native socket handle        CFStreamCreatePairWithSocket(kCFAllocatorDefault, self.connectedSocketHandle,                                     &readStream, &writeStream);                // Do the rest        return [self setupSocketStreams];    }        // Nothing was passed, connection is not possible    return NO;}// Further setup socket streams that were created by one of our 'init' methods- (BOOL) setupSocketStreams{    // Make sure streams were created correctly    if ( readStream == nil || writeStream == nil ) {        [self close];        return NO;    }        // Create buffers    incomingDataBuffer = [[NSMutableData alloc] init];    outgoingDataBuffer = [[NSMutableData alloc] init];        // Indicate that we want socket to be closed whenever streams are closed    CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);    CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);        // We will be handling the following stream events    CFOptionFlags registeredEvents = kCFStreamEventOpenCompleted | kCFStreamEventHasBytesAvailable                                    | kCFStreamEventCanAcceptBytes | kCFStreamEventEndEncountered                                    | kCFStreamEventErrorOccurred;        // Setup stream context - reference to 'self' will be passed to stream event handling callbacks    CFStreamClientContext ctx = {0, self, NULL, NULL, NULL};        // Specify callbacks that will be handling stream events    CFReadStreamSetClient(readStream, registeredEvents, readStreamEventHandler, &ctx);    CFWriteStreamSetClient(writeStream, registeredEvents, writeStreamEventHandler, &ctx);        // Schedule streams with current run loop    CFReadStreamScheduleWithRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);    CFWriteStreamScheduleWithRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);        // Open both streams    if ( !CFReadStreamOpen(readStream) || !CFWriteStreamOpen(writeStream)) {        [self close];        return NO;    }        return YES;}// Close connection- (void) close{    // Cleanup read stream    if ( readStream != nil ) {        CFReadStreamUnscheduleFromRunLoop(readStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);        CFReadStreamClose(readStream);        CFRelease(readStream);        readStream = NULL;    }        // Cleanup write stream    if ( writeStream != nil ) {        CFWriteStreamUnscheduleFromRunLoop(writeStream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);        CFWriteStreamClose(writeStream);        CFRelease(writeStream);        writeStream = NULL;    }        // Cleanup buffers    [incomingDataBuffer release];    incomingDataBuffer = NULL;        [outgoingDataBuffer release];    outgoingDataBuffer = NULL;           // Reset all other variables    [self clean];}#pragma mark - Send or Recv data // Send network message- (void) sendNetworkPacket:(NSDictionary *)packet{    // Encode packet    NSData * rawPacket = [NSKeyedArchiver archivedDataWithRootObject:packet];        // Write header: lengh of raw packet    NSInteger packetLength = [rawPacket length];    [outgoingDataBuffer appendBytes:&packetLength length:sizeof(int)];        // Write body: encoded NSDictionary    [outgoingDataBuffer appendData:rawPacket];        // Try to write to stream    [self writeOutgoingBufferToStream];}#pragma mark Read stream methods// Dispatch readStream eventsvoid readStreamEventHandler(CFReadStreamRef stream, CFStreamEventType eventType, void *info){    Connection* connection = (Connection*)info;    [connection readStreamHandleEvent:eventType];}// Handle events from the read stream- (void) readStreamHandleEvent:(CFStreamEventType)event{    // Stream successfully opened    if ( event == kCFStreamEventOpenCompleted ) {        readStreamOpen = YES;    }    // New data has arrived    else if ( event == kCFStreamEventHasBytesAvailable ) {        // Read as many bytes from the stream as possible and try to extract meaningful packets        [self readFromStreamIntoIncomingBuffer];    }    // Connection has been terminated or error encountered (we treat them the same way)    else if ( event == kCFStreamEventEndEncountered || event == kCFStreamEventErrorOccurred ) {        // Clean everything up        [self close];                // If we haven't connected yet then our connection attempt has failed        if ( !readStreamOpen || !writeStreamOpen ) {            [delegate connectionAttemptFailed:self];        }        else {            [delegate connectionTerminated:self];        }    }}// Read as many bytes from the stream as possible and try to extract meaningful packets- (void) readFromStreamIntoIncomingBuffer{    // Temporary buffer to read data into    UInt8 buf[1024];        // Try reading while there is data    while( CFReadStreamHasBytesAvailable(readStream) ) {          CFIndex len = CFReadStreamRead(readStream, buf, sizeof(buf));        if ( len <= 0 ) {            // Either stream was closed or error occurred. Close everything up and treat this as "connection terminated"            [self close];            [delegate connectionTerminated:self];            return;        }                [incomingDataBuffer appendBytes:buf length:len];    }        // Try to extract packets from the buffer.    //    // Protocol: header + body    //  header: an integer that indicates length of the body    //  body: bytes that represent encoded NSDictionary        // We might have more than one message in the buffer - that's why we'll be reading it inside the while loop    while( YES ) {        // Did we read the header yet?        if ( packetBodySize == -1 ) {            // Do we have enough bytes in the buffer to read the header?            if ( [incomingDataBuffer length] >= sizeof(int) ) {                // extract length                memcpy(&packetBodySize, [incomingDataBuffer bytes], sizeof(int));                                // remove that chunk from buffer                NSRange rangeToDelete = {0, sizeof(int)};                [incomingDataBuffer replaceBytesInRange:rangeToDelete withBytes:NULL length:0];            }            else {                // We don't have enough yet. Will wait for more data.                break;            }        }                // We should now have the header. Time to extract the body.        if ( [incomingDataBuffer length] >= packetBodySize ) {            // We now have enough data to extract a meaningful packet.            NSData* raw = [NSData dataWithBytes:[incomingDataBuffer bytes] length:packetBodySize];            NSDictionary* packet = [NSKeyedUnarchiver unarchiveObjectWithData:raw];                        // Tell our delegate about it            [delegate receivedNetworkPacket:packet viaConnection:self];                        // Remove that chunk from buffer            NSRange rangeToDelete = {0, packetBodySize};            [incomingDataBuffer replaceBytesInRange:rangeToDelete withBytes:NULL length:0];                        // We have processed the packet. Resetting the state.            packetBodySize = -1;        }        else {            // Not enough data yet. Will wait.            break;        }    }}#pragma mark Write stream methods// Dispatch writeStream event handlingvoid writeStreamEventHandler(CFWriteStreamRef stream, CFStreamEventType eventType, void *info){    Connection* connection = (Connection*)info;    [connection writeStreamHandleEvent:eventType];}// Handle events from the write stream- (void) writeStreamHandleEvent:(CFStreamEventType)event{    // Stream successfully opened    if ( event == kCFStreamEventOpenCompleted ) {        writeStreamOpen = YES;    }        // Stream has space for more data to be written    else if ( event == kCFStreamEventCanAcceptBytes ) {        // Write whatever data we have, as much as stream can handle        [self writeOutgoingBufferToStream];    }    // Connection has been terminated or error encountered (we treat them the same way)    else if ( event == kCFStreamEventEndEncountered || event == kCFStreamEventErrorOccurred ) {        // Clean everything up        [self close];                // If we haven't connected yet then our connection attempt has failed        if ( !readStreamOpen || !writeStreamOpen ) {            [delegate connectionAttemptFailed:self];        }        else {            [delegate connectionTerminated:self];        }    }}// Write whatever data we have, as much of it as stream can handle- (void) writeOutgoingBufferToStream{    // Is connection open?    if ( !readStreamOpen || !writeStreamOpen ) {        // No, wait until everything is operational before pushing data through        return;    }        // Do we have anything to write?    if ( [outgoingDataBuffer length] == 0 ) {        return;    }        // Can stream take any data in?    if ( !CFWriteStreamCanAcceptBytes(writeStream) ) {         return;    }        // Write as much as we can    CFIndex writtenBytes = CFWriteStreamWrite(writeStream, [outgoingDataBuffer bytes], [outgoingDataBuffer length]);        if ( writtenBytes == -1 ) {        // Error occurred. Close everything up.        [self close];        [delegate connectionTerminated:self];        return;    }        // Remove that chunk from buffer    NSRange range = {0, writtenBytes};    [outgoingDataBuffer replaceBytesInRange:range withBytes:NULL length:0];}@end


 

////  ConnectionDelegate.h//#import <Foundation/Foundation.h>@class Connection;@protocol ConnectionDelegate- (void) connectionAttemptFailed:(Connection*)connection;- (void) connectionTerminated:(Connection*)connection;- (void) receivedNetworkPacket:(NSDictionary*)message viaConnection:(Connection*)connection;@end


 

原创粉丝点击