2009-06-24 9 views
8

Ok, ho un problema con la creazione di un socket utilizzando Objective-C. Se darai un'occhiata al mio codice qui sotto, attraverso l'aiuto con codice di esempio e altre fonti, sono stato in grado di costruire un socket completo credo. Il problema è che quando lo compilo, si costruisce bene (senza problemi di sintassi), ma non ci sono socket che vengono creati. Come noterai, ho commentato molte cose in Server2 e ho isolato il problema fin dall'inizio quando creo la struct per listeningSocket. A proposito, se questo aiuta, fa parte del lato server dell'applicazione server-client. Qualcuno sa perché avrei avuto questo problema? Tutto sembrava funzionare bene ieri, e stamattina ho pensato di adottare un approccio diverso per costruire le prese, quindi ho provato questo. Grazie per qualsiasi aiuto!Problema con la creazione di socket tramite CFSocket in Objective-C (app per iPhone)

Server_TrialViewController.m

#include <CFNetwork/CFSocketStream.h> 
#import <UIKit/UIKit.h> 
#import "Server2.h" 
#import "Client_Test.h" 

@interface Server_TrialViewController : UIViewController { 
    IBOutlet UIButton *ServerButton; 
    IBOutlet UIButton *ClientButton; 
    IBOutlet UILabel *statusLabel; 
    Server2 *server; 
    Client_Test *client; 
} 

@property(nonatomic, retain) UILabel *statusLabel; 
@property(nonatomic, retain) Server2 *server; 
@property(nonatomic, retain) Client_Test *client; 

-(IBAction)serverButtonPressed; 
-(IBAction)clientButtonPressed; 
//-(void)sendMessageWithServer:(Server_Test *)SERVER AndClient:(Client_Test *)CLIENT; 

@end 

Server_TrialViewController.h

#import "Server_TrialViewController.h" 

@implementation Server_TrialViewController 
@synthesize statusLabel; 
@synthesize server; 
@synthesize client; 

-(IBAction)serverButtonPressed { 
    if ([server start]) { 
     [statusLabel setText:@"Success"]; 
    } 
    else { 
     if (server.status == NULL) { 
      [statusLabel setText: @"No Server: No statUpdate"]; 
     } 
     else { 
      [statusLabel setText: @"No Server: Found statUpdate"]; 
     } 
    }  
} 


-(IBAction)clientButtonPressed { 
    if ([client start]) { 
     [statusLabel setText:@"Client Started"]; 
    } 
    else { 
     [statusLabel setText:@"Client Not Started"]; 
    } 
} 


- (void)didReceiveMemoryWarning { 
    [super didReceiveMemoryWarning]; // Releases the view if it doesn't have a superview 
    // Release anything that's not essential, such as cached data 
} 


- (void)dealloc { 
    [super dealloc]; 
} 

@end 

Server2.h

#import <Foundation/Foundation.h> 
#import "Server2Delegate.h" 

@interface Server2 : NSObject 
{ 
    uint16_t port; 
    CFSocketRef listeningSocket; 
    id<Server2Delegate> delegate; 
    NSNetService* netService; 
    NSString *status; 
} 

// Initialize connection 
- (BOOL)start; 
- (void)stop; 

// Delegate receives various notifications about the state of our server 
@property(nonatomic,retain) id<Server2Delegate> delegate; 
@property(nonatomic, retain) NSString *status; 

@end 

Server2.m

#include <sys/socket.h> 
#include <netinet/in.h> 
#include <unistd.h> 
#include <CFNetwork/CFSocketStream.h> 

#import "Server2.h" 
#import "Connection2.h" 
#import "AppConfig2.h" 

// Declare some private properties and methods 
@interface Server2() 
@property(nonatomic,assign) uint16_t port; 
@property(nonatomic,retain) NSNetService* netService; 

-(BOOL)createServer; 
-(void)terminateServer; 

@end 

// Implementation of the Server interface 
@implementation Server2 

@synthesize delegate; 
@synthesize port, netService; 
@synthesize status; 

// Cleanup 
- (void)dealloc 
{ 
    self.netService = nil; 
    self.delegate = nil; 
    [super dealloc]; 
} 


// Create server and announce it 
- (BOOL)start 
{ 
    // Start the socket server 
    if (! [self createServer]) 
    { 
     status = @"Server Not Created"; 
     return FALSE; 
    } 
    status = @"Server Created"; 
    return TRUE; 
} 


// Close everything 
- (void)stop { 
    [self terminateServer]; 
} 

#pragma mark Callbacks 

// Handle new connections 
- (void)handleNewNativeSocket:(CFSocketNativeHandle)nativeSocketHandle { 
    Connection2* connection = [[[Connection2 alloc] initWithNativeSocketHandle:nativeSocketHandle] autorelease]; 

    // In case of errors, close native socket handle 
    if (connection == nil) { 
     close(nativeSocketHandle); 
     return; 
    } 

    // finish connecting 
    if (! [connection connect]) { 
     //status = @"Connection Not Made"; 
     [connection close]; 
     return; 
    } 

    //status = @"Connection Made"; 

    // Pass this on to our delegate 
    [delegate handleNewConnection:connection]; 
} 


// This function will be used as a callback while creating our listening socket via 'CFSocketCreate' 
static void serverAcceptCallback(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info) { 
    Server2 *server = (Server2*)info; 

    // We can only process "connection accepted" calls here 
    if (type != kCFSocketAcceptCallBack) { 
     return; 
    } 

    // for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle 
    CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle*)data; 

    [server handleNewNativeSocket:nativeSocketHandle]; 
} 


#pragma mark Sockets and streams 

- (BOOL)createServer 
{ 
    //// PART 1: Create a socket that can accept connections 

    // Socket context 
    // struct CFSocketContext { 
    // CFIndex version; 
    // void *info; 
    // CFAllocatorRetainCallBack retain; 
    // CFAllocatorReleaseCallBack release; 
    // CFAllocatorCopyDescriptionCallBack copyDescription; 
    // }; 
    CFSocketContext socketContext = {0, self, NULL, NULL, NULL}; 

    listeningSocket = CFSocketCreate(
            kCFAllocatorDefault, 
            PF_INET,  // The protocol family for the socket 
            SOCK_DGRAM, // The socket type to create 
            IPPROTO_UDP, // The protocol for the socket. TCP vs UDP. 
            0, //kCFSocketAcceptCallBack, // New connections will be automatically accepted and the callback is called with the data argument being a pointer to a CFSocketNativeHandle of the child socket. 
            NULL, //(CFSocketCallBack)&serverAcceptCallback, 
            &socketContext); 

    // Previous call might have failed 
    if (listeningSocket == NULL) { 
     status = @"listeningSocket Not Created"; 
     return FALSE; 
    } 
    else { 
     status = @"listeningSocket Created"; 
     return TRUE; 
    } 
} 
    /* 
    // getsockopt will return existing socket option value via this variable 
    int existingValue = 1; 

    // Make sure that same listening socket address gets reused after every connection 
    setsockopt(CFSocketGetNative(listeningSocket), 
       SOL_SOCKET, SO_REUSEADDR, (void *)&existingValue, 
       sizeof(existingValue)); 


    //// PART 2: Bind our socket to an endpoint. 
    // We will be listening on all available interfaces/addresses. 
    // Port will be assigned automatically by kernel. 
    struct sockaddr_in socketAddress; 
    memset(&socketAddress, 0, sizeof(socketAddress)); 
    socketAddress.sin_len = sizeof(socketAddress); 
    socketAddress.sin_family = AF_INET; // Address family (IPv4 vs IPv6) 
    socketAddress.sin_port = 0;   // Actual port will get assigned automatically by kernel 
    socketAddress.sin_addr.s_addr = htonl(INADDR_ANY); // We must use "network byte order" format (big-endian) for the value here 

    // Convert the endpoint data structure into something that CFSocket can use 
    NSData *socketAddressData = 
    [NSData dataWithBytes:&socketAddress length:sizeof(socketAddress)]; 

    // Bind our socket to the endpoint. Check if successful. 
    if (CFSocketSetAddress(listeningSocket, (CFDataRef)socketAddressData) != kCFSocketSuccess) { 
     // Cleanup 
     if (listeningSocket != NULL) { 
      status = @"Socket Not Binded"; 
      CFRelease(listeningSocket); 
      listeningSocket = NULL; 
     } 

     return FALSE; 
    } 
    status = @"Socket Binded"; 

    //// PART 3: Find out what port kernel assigned to our socket 
    // We need it to advertise our service via Bonjour 
    NSData *socketAddressActualData = [(NSData *)CFSocketCopyAddress(listeningSocket) autorelease]; 

    // Convert socket data into a usable structure 
    struct sockaddr_in socketAddressActual; 
    memcpy(&socketAddressActual, [socketAddressActualData bytes], 
      [socketAddressActualData length]); 

    self.port = ntohs(socketAddressActual.sin_port); 

    //// PART 4: Hook up our socket to the current run loop 
    CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent(); 
    CFRunLoopSourceRef runLoopSource = CFSocketCreateRunLoopSource(kCFAllocatorDefault, listeningSocket, 0); 
    CFRunLoopAddSource(currentRunLoop, runLoopSource, kCFRunLoopCommonModes); 
    CFRelease(runLoopSource); 

    return TRUE; 
} 
*/ 

- (void) terminateServer { 
    if (listeningSocket != nil) { 
     CFSocketInvalidate(listeningSocket); 
     CFRelease(listeningSocket); 
     listeningSocket = nil; 
    } 
} 


#pragma mark - 
#pragma mark NSNetService Delegate Method Implementations 

// Delegate method, called by NSNetService in case service publishing fails for whatever reason 
- (void)netService:(NSNetService*)sender didNotPublish:(NSDictionary*)errorDict { 
    if (sender != self.netService) { 
     return; 
    } 

    // Stop socket server 
    [self terminateServer]; 
} 

@end 

risposta

4

Per le persone che cercano informazioni sul server CFSocket, ecco la risposta: Il codice sopra riportato funziona correttamente se si modifica "SOCK_DGRAM" in "SOCK_STREAM".

+0

CFSocketStream include la parola "stream" per indicare che è per le connessioni orientate al flusso. In Apple, pensano che questo sia ovvio come può essere, ma chiaramente non lo è. – uchuugaka

1

Hai provato a impostare kCFSocketAcceptCallBack su un valore diverso da 0?

Se sei interessato alla programmazione di socket su Mac OS X o iPhone, ti suggerisco di guardare this example dalla documentazione Apple.

Problemi correlati