2009-06-24 6 views
8

Ok, j'ai un problème avec la construction d'une socket avec Objective-C. Si vous jetez un oeil à mon code ci-dessous, grâce à l'aide de l'exemple de code et d'autres sources, j'ai été en mesure de construire un socket complet, je crois. Le problème est que lorsque je le compile, il se construit très bien (pas de problèmes de syntaxe), mais il n'y a pas de socket créé. Comme vous remarquerez que j'ai commenté beaucoup de choses dans Server2.m et ai isolé le problème au tout début quand je crée la structure pour le listeningSocket. En passant, si cela aide, il fait partie du côté serveur de l'application client-serveur. Est-ce que quelqu'un sait pourquoi je vais avoir ce problème? Tout semblait fonctionner correctement hier, et ce matin, j'ai pensé que j'allais adopter une approche différente pour construire les prises, alors j'ai essayé cela. Merci pour toute aide!Problème lors de la création de sockets à l'aide de CFSocket dans Objective-C (application 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 

Répondre

4

Pour les personnes qui recherchent des informations sur le serveur CFSocket, voici la réponse: Le code ci-dessus fonctionne correctement si vous remplacez "SOCK_DGRAM" par "SOCK_STREAM".

+0

CFSocketStream inclut le mot "flux" pour indiquer qu'il s'agit de connexions orientées flux. Dans Apple, ils pensent que c'est tout aussi évident que possible, mais ce n'est clairement pas le cas. – uchuugaka

1

Avez-vous essayé de définir kCFSocketAcceptCallBack sur autre chose que 0?

Si vous êtes intéressé par la programmation de socket sur Mac OS X ou l'iPhone, je vous suggère de regarder this example dans la documentation d'Apple.

Questions connexes