ブロードキャストが機能しました(iOS 10で)
パーソナル ホットスポット モードで iOS 10 でブロードキャストを動作させる方法を見つけたので、2 番目の回答を投稿します。解決策は少し複雑ですが、これを機能させる方法は次のとおりです。
getifaddrs(if)
すべてのインターフェースをループするために使用します ( do {} while (if = if->ifa_next)
)
- ループバック インターフェイスを拒否する (
if->ifa_flags & IFF_LOOPBACK
)
- ブロードキャストをサポートするインターフェースのみをフィルタリングする (
if->ifa_flags & IFF_BROADCAST
)
- でソケットを作成します
int sock = socket()
- ブロードキャストを有効にする:
int yes = 1; setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes)
- ブロードキャスト アドレスに接続します。
connect(sock, if->ifa_dstaddr, if->ifa_dstaddr->sa_len)
- 今すぐ
send()
あなたのメッセージを送信するために使用してください!
これは、iPhone が WiFi ネットワークに接続されているときと、パーソナル ホットスポット モードのときの両方で動作することを確認しています。
完全なサンプル コード
#include <ifaddrs.h>
#include <arpa/inet.h>
#include <net/if.h>
-(IBAction)sayHello:(id)sender {
// fetch a linked list of all network interfaces
struct ifaddrs *interfaces;
if (getifaddrs(&interfaces) == -1) {
NSLog(@"getifaddrs() failed: %s", strerror(errno));
return;
}
// loop through the linked list
for(struct ifaddrs *interface=interfaces; interface; interface=interface->ifa_next) {
// ignore loopback interfaces
if (interface->ifa_flags & IFF_LOOPBACK) continue;
// ignore interfaces that don't have a broadcast address
if (!(interface->ifa_flags & IFF_BROADCAST) || interface->ifa_dstaddr == NULL) continue;
// check the type of the address (IPv4, IPv6)
int protocol_family;
struct sockaddr_in ipv4_addr = {0};
struct sockaddr_in6 ipv6_addr = {0};
struct sockaddr *addr;
if (interface->ifa_dstaddr->sa_family == AF_INET) {
if (interface->ifa_dstaddr->sa_len > sizeof ipv4_addr) {
NSLog(@"Address too big");
continue;
}
protocol_family = PF_INET;
memcpy(&ipv4_addr, interface->ifa_dstaddr, interface->ifa_dstaddr->sa_len);
ipv4_addr.sin_port = htons(16000);
addr = (struct sockaddr *)&ipv4_addr;
char text_addr[255] = {0};
inet_ntop(AF_INET, &ipv4_addr.sin_addr, text_addr, sizeof text_addr);
NSLog(@"Sending message to %s:%d", text_addr, ntohs(ipv4_addr.sin_port));
}
else if (interface->ifa_dstaddr->sa_family == AF_INET6) {
if (interface->ifa_dstaddr->sa_len > sizeof ipv6_addr) {
NSLog(@"Address too big");
continue;
}
protocol_family = PF_INET6;
memcpy(&ipv6_addr, interface->ifa_dstaddr, interface->ifa_dstaddr->sa_len);
ipv6_addr.sin6_port = htons(16000);
addr = (struct sockaddr *)&ipv6_addr;
char text_addr[255] = {0};
inet_ntop(AF_INET6, &ipv6_addr.sin6_addr, text_addr, sizeof text_addr);
NSLog(@"Sending message to %s:%d", text_addr, ntohs(ipv6_addr.sin6_port));
}
else {
NSLog(@"Unsupported protocol: %d", interface->ifa_dstaddr->sa_family);
continue;
}
// create a socket
int sock = socket(protocol_family, SOCK_DGRAM, IPPROTO_UDP);
if (sock == -1) {
NSLog(@"socket() failed: %s", strerror(errno));
continue;
}
// configure the socket for broadcast mode
int yes = 1;
if (-1 == setsockopt(sock, SOL_SOCKET, SO_BROADCAST, &yes, sizeof yes)) {
NSLog(@"setsockopt() failed: %s", strerror(errno));
}
// create some bytes to send
NSString *message = @"Hello world!\n";
NSData *data = [message dataUsingEncoding:NSUTF8StringEncoding];
if (-1 == connect(sock, addr, addr->sa_len)) {
NSLog(@"connect() failed: %s", strerror(errno));
}
// send the message
ssize_t sent_bytes = send(sock, data.bytes, data.length, 0);
if (sent_bytes == -1) {
NSLog(@"send() failed: %s", strerror(errno));
}
else if (sent_bytes<data.length) {
NSLog(@"send() sent only %d of %d bytes", (int)sent_bytes, (int)data.length);
}
// close the socket! important! there is only a finite number of file descriptors available!
if (-1 == close(sock)) {
NSLog(@"close() failed: %s", strerror(errno));
}
}
freeifaddrs(interfaces);
}
このサンプル メソッドは、ポート 16000 で UDP メッセージをブロードキャストします。
デバッグには、ツールを使用できますsocat
。コンピューターで次のコマンドを実行するだけです (電話と同じネットワーク上にある必要があります)。
socat UDP-RECV:16000 STDOUT