CFSocketでマルチキャスト送受信
CF系APIを使ってマルチキャストUDPパケットを送信するサンプルと受信するサンプルです。 エラー処理等かなりいい加減なのでご注意下さい。 説明文をそのうち書くかも知れませんが、今は面倒なのでコードを解読して下さい。
送信側サンプルコード
送信側サンプルは、IP_MULTICAST_IFを利用してマルチキャスト送出インターンフェースを指定しています。 マルチキャスト送出インターフェースはネットワークインターフェースに付いているIPv4アドレスで指定します。
#import <Cocoa/Cocoa.h>
#import <netinet/in.h>
#import <sys/socket.h>
#import <arpa/inet.h>
#import <errno.h>
NSAutoreleasePool *pool = NULL;
void
showerror_and_release_pool()
{
NSError *nserr;
nserr = [NSError errorWithDomain:NSPOSIXErrorDomain
code:errno
userInfo:NULL];
NSLog(@"%@", [nserr localizedDescription]);
[pool release];
}
int
main()
{
CFSocketRef sock;
CFSocketError err;
pool = [[NSAutoreleasePool alloc] init];
sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM,
IPPROTO_UDP,
kCFSocketNoCallBack,
NULL, NULL);
if (sock == NULL) {
showerror_and_release_pool();
return 1;
}
struct sockaddr_in dest;
memset(&dest, 0, sizeof(dest));
dest.sin_len = sizeof(dest);
dest.sin_family = AF_INET;
dest.sin_port = htons(10000);
inet_aton("239.192.1.2", &dest.sin_addr); /* change here */
in_addr_t ifaddr;
ifaddr = inet_addr("10.1.2.3"); /* change here */
if (setsockopt(CFSocketGetNative(sock),
IPPROTO_IP,
IP_MULTICAST_IF,
(char *)&ifaddr, sizeof(ifaddr)) != 0) {
showerror_and_release_pool();
return 1;
}
CFDataRef destData = CFDataCreate(NULL, (unsigned char *)&dest, sizeof(dest));
CFDataRef msgData = CFDataCreate(NULL, (unsigned char *)"HOGE", 4);
err = CFSocketSendData(sock, destData, msgData, 4);
if (err != kCFSocketSuccess) {
showerror_and_release_pool();
return 1;
}
[pool release];
return 0;
}
受信側サンプルコード
IP_ADD_MEMBERSHIPでマルチキャストグループにJOINしているのがポイントです。
#import <Cocoa/Cocoa.h>
#import <netinet/in.h>
#import <sys/socket.h>
#import <arpa/inet.h>
#import <errno.h>
NSAutoreleasePool *pool = NULL;
void
myCallbackFunc(CFSocketRef socket, CFSocketCallBackType type,
CFDataRef addr, const void *pData, void *pInfo) {
if (type != kCFSocketDataCallBack) {
NSLog(@"invalid type : %d", type);
return;
}
NSLog(@"len=%d, [%s]",
CFDataGetLength((CFDataRef)pData),
CFDataGetBytePtr((CFDataRef)pData));
CFRunLoopStop(CFRunLoopGetCurrent());
return;
}
void
showerror_and_release_pool()
{
NSError *nserr;
nserr = [NSError errorWithDomain:NSPOSIXErrorDomain
code:errno
userInfo:NULL];
NSLog(@"%@", [nserr localizedDescription]);
[pool release];
}
int
main()
{
CFSocketRef sock;
NSError *nserr;
pool = [[NSAutoreleasePool alloc] init];
sock = CFSocketCreate(kCFAllocatorDefault, PF_INET, SOCK_DGRAM,
IPPROTO_UDP,
kCFSocketDataCallBack,
(CFSocketCallBack)myCallbackFunc, NULL);
if (sock == NULL) {
showerror_and_release_pool();
return 1;
}
struct sockaddr_in myaddr;
memset(&myaddr, 0, sizeof(myaddr));
myaddr.sin_len = sizeof(myaddr);
myaddr.sin_family = AF_INET;
myaddr.sin_port = htons(10000);
myaddr.sin_addr.s_addr = INADDR_ANY;
CFDataRef myaddrData = CFDataCreate(NULL,
(unsigned char *)&myaddr, sizeof(myaddr));
CFSocketError serr;
serr = CFSocketSetAddress(sock, myaddrData);
if (serr != kCFSocketSuccess) {
showerror_and_release_pool();
return 1;
}
struct ip_mreq mreq;
memset(&mreq, 0, sizeof(mreq));
mreq.imr_interface.s_addr = INADDR_ANY;
mreq.imr_multiaddr.s_addr = inet_addr("239.192.1.2"); /* change here */
if (setsockopt(CFSocketGetNative(sock),
IPPROTO_IP,
IP_ADD_MEMBERSHIP,
(char *)&mreq, sizeof(mreq)) != 0) {
showerror_and_release_pool();
return 1;
}
CFRunLoopSourceRef src;
src = CFSocketCreateRunLoopSource(kCFAllocatorDefault, sock, 0);
CFRunLoopAddSource(CFRunLoopGetCurrent(), src, kCFRunLoopCommonModes);
CFRunLoopRun();
CFRelease(src);
CFRelease(myaddrData);
CFRelease(sock);
[pool release];
return 0;
}