2009-06-24 17 views
8

好的,我在使用Objective-C構建套接字時遇到了問題。如果你看看下面的代碼,通過示例代碼和其他來源的幫助,我能夠構建一個完整的socket,我相信。問題是,當我編譯它時,它建立良好(沒有語法問題),但沒有創建套接字。正如你會注意到我已經在Server2.m中註釋了很多東西,並且在爲listenSocket創建結構時將問題隔離開始。順便說一句,如果這有幫助,它是服務器端客戶端應用程序的服務器端的一部分。有誰知道我爲什麼會遇到這個問題?一切似乎都在昨天正常工作,今天早上我想我會採取不同的方法來構建套接字,所以我試了一下。謝謝你的幫助!在Objective-C(iPhone應用程序)中使用CFSocket創建套接字的問題

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 

回答

4

爲人們尋找有關CFSocket服務器的信息,這裏的答案:上面的代碼,如果你改變「SOCK_DGRAM」到「SOCK_STREAM」是工作的罰款。

+0

CFSocketStream包含單詞「流」以表示它是面向流的連接。在蘋果公司,他們認爲這很明顯,但事實並非如此。 – uchuugaka 2015-01-08 16:24:33

1

您是否嘗試將kCFSocketAcceptCallBack設置爲0以外的值?

如果你有興趣在Mac OS X或iPhone的socket編程,我建議你從蘋果公司的文檔,看看this example

相關問題