尝试在CoreFoundation中使用 CFSockets API 时遇到问题。我试图在端口上侦听并接受传入的连接。这似乎可以与以下代码一起使用,因为运行nc localhost 8118
会使终端处于连接状态。但是,永远不会调用回调方法handleConnect()
。阅读Apple文档后,看不到我在做什么错...我的代码:
#import <Foundation/Foundation.h>
#import <CoreFoundation/CoreFoundation.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "SocketManager.h"
@implementation SocketManager
- (instancetype)init
{
self = [super init];
if (self) {
self.port = 8118;
}
return self;
}
-(void)startListening
{
CFSocketContext ctxt = {0, CFBridgingRetain(self), NULL, NULL, NULL};
self.ipv4ListeningSocket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, IPPROTO_TCP, kCFSocketAcceptCallBack, (CFSocketCallBack)&handleConnect, &ctxt);
int yes = 1;
setsockopt(CFSocketGetNative(self.ipv4ListeningSocket), SOL_SOCKET, SO_REUSEADDR, (void *)&yes, sizeof(yes));
struct sockaddr_in addr4;
memset(&addr4, 0, sizeof(addr4));
addr4.sin_len = sizeof(addr4);
addr4.sin_family = AF_INET;
addr4.sin_port = htons(self.port);
addr4.sin_addr.s_addr = htonl(INADDR_ANY);
NSData *address4 = [NSData dataWithBytes:&addr4 length:sizeof(addr4)];
if (kCFSocketSuccess == CFSocketSetAddress(self.ipv4ListeningSocket, (CFDataRef)address4)) {
if (0 == [self port]) {
// now that the binding was successful, we get the port number
// -- we will need it for the v6 endpoint and for the NSNetService
NSData *addr = (__bridge_transfer NSData *)CFSocketCopyAddress(self.ipv4ListeningSocket);
memcpy(&addr4, [addr bytes], [addr length]);
self.port = ntohs(addr4.sin_port);
}
} else {
if (self.ipv4ListeningSocket) CFRelease(self.ipv4ListeningSocket);
self.ipv4ListeningSocket = NULL;
}
// set up the run loop sources for the sockets
CFRunLoopRef cfrl = CFRunLoopGetCurrent();
if (self.ipv4ListeningSocket) {
CFRunLoopSourceRef source4 = CFSocketCreateRunLoopSource(kCFAllocatorDefault, self.ipv4ListeningSocket, 0);
CFRunLoopAddSource(cfrl, source4, kCFRunLoopCommonModes);
CFRelease(source4);
}
}
static void handleConnect(CFSocketRef socket, CFSocketCallBackType type, CFDataRef address, const void *data, void *info)
{
NSLog(@"RECIEVED CONNECTION REQUEST \n");
if (kCFSocketAcceptCallBack == type) {
// for an AcceptCallBack, the data parameter is a pointer to a CFSocketNativeHandle
CFSocketNativeHandle nativeSocketHandle = *(CFSocketNativeHandle *)data;
uint8_t name[SOCK_MAXADDRLEN];
socklen_t namelen = sizeof(name);
NSData *peer = nil;
if (0 == getpeername(nativeSocketHandle, (struct sockaddr *)name, &namelen)) {
peer = [NSData dataWithBytes:name length:namelen];
}
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
CFStreamCreatePairWithSocket(kCFAllocatorDefault, nativeSocketHandle, &readStream, &writeStream);
if (readStream && writeStream) {
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
//[server handleNewConnectionFromAddress:peer inputStream:(__bridge NSInputStream *)readStream outputStream:(__bridge NSOutputStream *)writeStream];
} else {
// on any failure, need to destroy the CFSocketNativeHandle
// since we are not going to use it any more
close(nativeSocketHandle);
}
if (readStream) CFRelease(readStream);
if (writeStream) CFRelease(writeStream);
} else {
NSLog(@"No idea");
}
}
@end