在Objective-C(iPhone应用程序)中使用CFSocket创建套接字的问题

Jos*_*ley 8 sockets objective-c

好吧,我在使用Objective-C构建套接字时遇到问题.如果你看看我下面的代码,通过示例代码和其他来源的帮助,我能够构建一个完整的套接字,我相信.问题是,当我编译它时,它构建正常(没有语法问题),但没有创建套接字.正如您将注意到我在Server2.m中注释了很多内容,并在我为listenSocket创建结构时将问题隔离开来.顺便说一句,如果这有帮助,它是服务器 - 客户端应用程序的服务器端的一部分.有谁知道为什么我会遇到这个问题?昨天一切似乎工作正常,今天早上我想我会采用不同的方法来构建插座,所以我尝试了这个.谢谢你的帮助!

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

Leo*_*Leo 4

对于寻找有关 CFSocket 服务器信息的人,答案是:如果将“SOCK_DGRAM”更改为“SOCK_STREAM”,则上面的代码可以正常工作。