2010-02-16 1 views
1

Я пишу приложение Cocoa. В приложении есть сокет, и всякий раз, когда сокет становится читаемым, я хочу читать данные из сокета, обрабатывать данные и соответственно обновлять пользовательский интерфейс. Я хочу интегрировать проверку событий чтения в основной цикл, т. Е. Я хочу подключить сокет к основному циклу и иметь обратный вызов основного цикла, когда этот сокет становится читаемым.OS X: как смотреть события сокетов с NSRunLoop?

Я написал тестовое приложение, но по какой-то причине он не работает:

#include <stdio.h> 
#include <Foundation/NSAutoReleasePool.h> 
#include <Foundation/NSRunLoop.h> 
#include <Foundation/NSPort.h> 

@interface MyDelegate : NSObject <NSPortDelegate> { 
} 
- (void)handlePortMessage:(NSPortMessage *)portMessage; 
@end 

@implementation MyDelegate 
- (void)handlePortMessage:(NSPortMessage *)portMessage { 
    printf("Haiz\n"); 
} 
@end 

int 
main() { 
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; 
    NSSocketPort *server = [NSSocketPort alloc]; 
    MyDelegate *foo = [MyDelegate alloc]; 
    [server initWithTCPPort: 1234]; 
    [server setDelegate: foo]; 
    [[NSRunLoop mainRunLoop] addPort: server forMode: NSDefaultRunLoopMode]; 
    [[NSRunLoop mainRunLoop] run]; 
    [pool release]; 
    return 0; 
} 

Приложение должно прослушивать LOCALHOST порт 1234, и всякий раз, когда кто-то подключается к серверу или передает данные на сервер приложение должно печатать «Haiz» на консоли. Однако приложение ничего не делает. Сокет создан, и я могу подключиться к порту 1234, но приложение ничего не печатает на консоли.

Что я делаю неправильно?

+0

Помимо прочего, отправка 'alloc' в класс, но не отправка' init' в экземпляр. Вы полностью забудете об этом с помощью объекта MyDelegate, который хорошо показывает, почему вы всегда должны держать 'alloc' и' init' вместе в одном выражении сообщения: 'MyDelegate * foo = [[[MyDelegate alloc] init] autorelease];' Примечание также что вы должны освобождать объекты, которые вы выделяете. Просмотрите правила управления памятью: http://developer.apple.com/mac/library/documentation/General/Conceptual/DevPedia-CocoaCore/MemoryManagement.html –

ответ

1

Из документации:

объект NSSocketPort может быть использован в качестве конечной точки для распределенных объектных соединений.

Это не то, что вы здесь делаете.

Вы хотите либо NSFileHandle вокруг сокета дескриптора файла из BSD Sockets API илиCFSocket. Это позволит помещать сокет в цикл выполнения.

+0

NSFileHandle не является NSPort, и для него нет CFRunLoopSource, поэтому я не могу его подключить к основному циклу. – Hongli

+0

Я знаю, что NSFileHandle не является NSPort. NSPorts предназначены для IPC. Ваш метод делегата не вызывается, потому что вы никогда не получите сообщение порта в этом сокете. Что касается присоединения к циклу запуска, либо отправьте дескриптор файла сообщение acceptConnectionInBackgroundAndNotify, либо вместо него используйте CFSocket. –

+0

У меня создалось впечатление, что FoundationKit - это всего лишь объектная оболочка C вокруг CoreFoundation, но теперь кажется, что они совершенно разные и что есть некоторые вещи, которые я могу сделать с CoreFoundation, но не с FoundationKit? Причина, по которой я пытаюсь привязаться к FoundationKit, потому что я на самом деле пишу приложение в MacRuby, а не Objective C, и у него есть некоторые проблемы с указателями функций, которые ожидают API CoreFoundation. – Hongli

0

Вы хотите использовать NSSocketPort так, как вы это делаете, но затем создайте NSFileHandle, чтобы принимать соединения в сокете. Вы можете получить обратные вызовы в основном потоке точно так же, как вы ожидаете, сначала для новых подключений, а затем для данных по этим соединениям. Используйте это O'Reilly article и просто игнорируйте HTTP-материал.

Смежные вопросы