« もっとCore Foundation / CFStreamこそがtoll-freeだよ | ホーム | Core Foundation Hacks / iPhoneでも同じように動くのか? »
2011年5月16日
もっとCore Foundation / サーバソケットとCFStreamと私
で。
CFStream APIについて触れたかったのはこっち。CFStreamはネットワーク部分はいわゆるTCP/IPソケットと同じなので、connectとacceptによって通信路が確立される。
前のエントリで触れた内容ではクライアント側の実装、すなわちconnect側だったわけだが、もちろんサーバソケット(accept側)の実装もできる。ちょっと手間はかかるけれどもこんな感じ。
static void
_server_socket_callback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void* data, void* info)
{
CFSocketNativeHandle handle = *(CFSocketNativeHandle*)data;
NSLog(@"accepted. (s = %p, handle = %d)", s, handle);
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
CFStreamCreatePairWithSocket(kCFAllocatorDefault, handle, &readStream, &writeStream);
if (_setup_read_stream(readStream) != 0) {
CFRelease(readStream);
readStream = NULL;
}
if (_setup_write_stream(writeStream) != 0) {
CFRelease(writeStream);
writeStream = NULL;
}
NSLog(@"readStream = %p, writeStream = %p", readStream, writeStream);
}
static void
_do_server()
{
CFSocketContext context = { 0, NULL, NULL, NULL, NULL };
CFSocketRef socket = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_STREAM, 0, kCFSocketAcceptCallBack, _server_socket_callback, &context);
int yes = 1;
setsockopt(CFSocketGetNative(socket), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes));
struct sockaddr_in sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = INADDR_ANY;
sin.sin_port = htons(8888);
sin.sin_len = sizeof(struct sockaddr_in);
CFDataRef data = CFDataCreate(kCFAllocatorDefault, (UInt8*)&sin, sizeof(sin));
CFSocketSetAddress(socket, data);
CFRelease(data);
CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(kCFAllocatorDefault, socket, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopCommonModes);
CFRelease(source);
NSLog(@"socket = %p", socket);
}
- CFSocketCreate()でCFSocketオブジェクトを生成し、
- CFSocketSetAddress()でバインディングアドレスを指定、
- CFSocketCreateRunLoopSource()およびCFRunLoopAddSource()でRun LoopにCFSocketオブジェクトを登録、
- 最初のCFSocketCreate()で登録したコールバック(_server_socket_callback)にacceptされたソケットディスクリプタ(=CFSocketNativeHandle)が渡り、
- 4.のソケットディスクリプタからCFStreamCreatePairWithSocket()より、CFReadStream/CFWriteStreamを生成。
これ以降は前エントリの扱いと同じ。
んで。
このパターンで生成されたCFReadStream/CFWriteStreamは、CFReadStreamClose()/CFWriteStreamClose()してもTCP接続は閉じないという現象を確認してしまいました。これそういうもん?と色々調べたところ、CFReadStream/CFWriteStreamオブジェクトのプロパティkCFStreamPropertyShouldCloseNativeSocketをTRUE(kCFBooleanTrue)にするとちゃんと閉じてくれるようになった。
static void
_server_socket_callback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const void* data, void* info)
{
switch (type) {
case kCFSocketAcceptCallBack: {
CFSocketNativeHandle handle = *(CFSocketNativeHandle*)data;
NSLog(@"accepted. (s = %p, handle=%d)", s, handle);
CFReadStreamRef readStream = NULL;
CFWriteStreamRef writeStream = NULL;
CFStreamCreatePairWithSocket(kCFAllocatorDefault, handle, &readStream, &writeStream);
CFReadStreamSetProperty(readStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
CFWriteStreamSetProperty(writeStream, kCFStreamPropertyShouldCloseNativeSocket, kCFBooleanTrue);
if (_setup_read_stream(readStream) != 0) {
CFRelease(readStream);
readStream = NULL;
}
if (_setup_write_stream(writeStream) != 0) {
CFRelease(writeStream);
writeStream = NULL;
}
NSLog(@"readStream = %p, writeStream = %p", readStream, writeStream);
}
break;
}
}
トラックバック(0)
トラックバックURL: http://foursics.jp/cgi-bin/mt/mt-tb.cgi/340
コメントする