我正在尝试在Xcode中制作一个简单的TCP服务器,OS X上的Objective-C。
似乎连接被接受,并且我正在通过事件处理获得我应该获得的所有事件,但是当我尝试从事件内部的输入流中读取说有数据可供读取时,我收到以下错误消息:
错误域=NSPOSIXError域代码=9"无法完成操作。错误的文件描述符">
我的完整调试日志是:
handleConnect: ACCEPT
<< Open Complete
>> Open Complete
<< Has Bytes Available
Error Reading Stream
Error Domain=NSPOSIXErrorDomain Code=9 "The operation couldn’t be completed. Bad file descriptor"
Length: 0
<< Error Occured
Error Domain=NSPOSIXErrorDomain Code=9 "The operation couldn’t be completed. Bad file descriptor"
您可以看到输入流和输出流都发送"打开完成"事件,然后输入流发送"有可用字节数"事件,但从流读取失败。 读取失败后,输入流发送"发生错误"事件。
我不知道问题到底是什么。 顺便说一下,我正在尝试连接网络浏览器。 这是我编写的代码:
网络服务器:
#import "WebServer.h"
@implementation WebServer
- (id)init {
self = [super init];
if (self != nil) {
connections = nil;
}
return self;
}
- (void)start {
CFSocketRef myipv4cfsock = CFSocketCreate(
kCFAllocatorDefault,
PF_INET,
SOCK_STREAM,
IPPROTO_TCP,
kCFSocketAcceptCallBack, handleConnect, NULL);
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_len = sizeof(sin);
sin.sin_family = AF_INET;
sin.sin_port = htons(8080);
sin.sin_addr.s_addr= INADDR_ANY;
CFDataRef sincfd = CFDataCreate(
kCFAllocatorDefault,
(UInt8 *)&sin,
sizeof(sin));
CFSocketSetAddress(myipv4cfsock, sincfd);
CFRelease(sincfd);
CFRunLoopSourceRef socketsource = CFSocketCreateRunLoopSource(
kCFAllocatorDefault,
myipv4cfsock,
0);
CFRunLoopAddSource(
CFRunLoopGetCurrent(),
socketsource,
kCFRunLoopDefaultMode);
}
void handleConnect(CFSocketRef s, CFSocketCallBackType callbackType, CFDataRef address, const void *data, void *info) {
if (callbackType == kCFSocketAcceptCallBack) {
printf("handleConnect: ACCEPTn");
if (connections == nil) {
connections = [[NSMutableArray alloc] init];
}
CFReadStreamRef rs = NULL;
CFWriteStreamRef ws = NULL;
CFStreamCreatePairWithSocket(kCFAllocatorDefault, (CFSocketNativeHandle)data, &rs, &ws);
WebServerConnection *connection = [[WebServerConnection alloc] initWithInputStream:(__bridge NSInputStream *)rs outputStream:(__bridge NSOutputStream *)ws];
[connections addObject:connection];
return;
}
else {
printf("handleConnect: UNKNOWNn");
}
}
@end
当有人连接时:
#import "WebServerConnection.h"
@implementation WebServerConnection
- (id)init {
self = [super init];
if (self != nil) {
nativeSocket = 0;
readStream = nil;
writeStream = nil;
}
return self;
}
- (id)initWithInputStream:(NSInputStream *)is outputStream:(NSOutputStream *)os {
self = [self init];
if (self != nil) {
readStream = is;
writeStream = os;
[readStream setDelegate:self];
[writeStream setDelegate:self];
[readStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[writeStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[readStream open];
[writeStream open];
data = nil;
}
return self;
}
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
NSString *io = @"??";
if (aStream == readStream) {
io = @"<<";
}
else if (aStream == writeStream) {
io = @">>";
}
switch (eventCode) {
case NSStreamEventOpenCompleted:
printf("%s ", [io UTF8String]);
printf("Open Completen");
break;
case NSStreamEventHasBytesAvailable:
{
printf("%s ", [io UTF8String]);
printf("Has Bytes Availablen");
if (data == nil) {
data = [[NSMutableData alloc] init];
}
uint8_t buffer[1024];
NSInteger actuallyRead = [readStream read:(uint8_t *)buffer maxLength:sizeof(buffer)];
if (actuallyRead > 0) {
[data appendBytes:buffer length:actuallyRead];
}
else {
if (actuallyRead == 0) {
printf("End of Datan");
}
else {
printf("Error Reading Streamn");
NSError *error = [readStream streamError];
printf("%sn", [[error description] UTF8String]);
}
}
printf("Length: %lun", [data length]);
break;
}
case NSStreamEventHasSpaceAvailable:
printf("%s ", [io UTF8String]);
printf("Has Space Availablen");
break;
case NSStreamEventEndEncountered:
printf("%s ", [io UTF8String]);
printf("End Encounteredn");
break;
case NSStreamEventErrorOccurred:
{
printf("%s ", [io UTF8String]);
printf("Error Occuredn");
NSError *error = [aStream streamError];
printf("%sn", [[error description] UTF8String]);
[readStream setDelegate:nil];
[writeStream setDelegate:nil];
[readStream close];
[writeStream close];
[readStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[writeStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
break;
}
case NSStreamEventNone:
{
printf("%s ", [io UTF8String]);
printf("Nonen");
break;
}
default:
printf("%s ", [io UTF8String]);
printf("Default Clausen");
break;
}
}
@end
似乎我把错误的数据传递给了'CFStreamCreatePairWithSocket(( 函数。
CFStreamCreatePairWithSocket(kCFAllocatorDefault, *(CFSocketNativeHandle *)data, &rs, &ws);
请注意,我忘了投*(CFSocketNativeHandle *)data
,只是发送(CFSocketNativeHandle)data
。