iPhoneでC言語を使ってUDP通信してみよう

/




iOS -> Mac with UDP





PHPからプログラミングを入門した軟弱者の私としては、HTTP以下の低位レイヤーが苦手です。今までなんとなく誤魔化してきましたが、Arduinoに触れたことで学習意欲が湧きました。そこでiOSからMacへUDP送信を行なってみることにしました。学習がてらNSStreamを使わずに、あえてC言語で書いてみることにしました。

ところでUDPという言葉は、User Datagram Protocolの略です。データグラムというのは、配送が成功したかどうかの確認はしないので届くかどうか保証されないですよ、という意味なのだそうです。


Mac側でUDPサーバーを立ち上げる



まずはMacのターミナルを開き、netcatコマンドを使ってUDPサーバーを立ち上げます。
たったの一行でUDPサーバーが立ち上がってしまいます。シェルというのは大変便利ですね。
nc -u -l 8888

ところで、ポートが解放されているかどうかの確認で少しハマりました。そもそもUDPは一方的な送信なので、ポートが開いているかどうかのスキャンはできないということを分かっていませんでした。
例えば、8888ポートが開いているかどうかのコマンドは次のようになります。
nc -vz 192.168.100.101 8888

UDPサーバーを対象にはスキャンできません。次のように、TCPサーバーとして立ち上げた場合はポートスキャンできるようになります。
nc -l 8888

TCPのハンドシェイクを利用しているということなのでしょうね。


iOSプログラミング、UDPクライアントを作る



iOSのプログラミングを書いていきましょう。
Objective-CでC言語の関数を使いたい場合、.mファイルを.mmの拡張子にすれば良いようです。



このように、UDPクライアントのプログラムは驚くほど簡単に書けることがわかりました。それでも慣れないC言語の関数が出てきたので少し調べてみることにしました。
まず、sockaddr_inという構造体に送信先アドレスやポート番号を設定しています。
そして、socketというクラスを初期化してます。初期化の時に、SOCK_DGRAMを指定してあげればUDPで通信してくれるようになります。
また、AF_INETはIPv4のインターネットプロトコルで通信するということのようです。
さて、これで先ほどMac側で立ち上げたターミナル画面に"HELLO"というメッセージが表示されるようになりました。


UDPのプロトコル仕様を確認してみる




UDPプロトコルの仕様を確認してみると、ヘッダ部とデータ部に別れているのがわかります。とてもシンプルで、送信のイメージがつきやすいですね。
また、ポートが16ビットの長さということは、2の16乗 = 65536番まで指定できるということがわかります。


Mac -> iOS with UDP




UDPのことがだいぶ分かってきたところで、今度は、Mac側からUDPソケットをiPhoneへ送信しみたいと思います。

UDPサーバーのプログラミングを行なっていきます。先ほどのUDPクライアントのプログラムよりは複雑になってきますが、丁寧にみていけば難しいことはありません。
注意するべきところは、UDPソケットを受信するためのrecv関数はメインスレッドで動かしてしまうと、UIが固まってしまいます。そのため、NSThreadを使ってスレッド処理になっています。
下記プログラムは、buf配列のメモリ解放を行ってないのでご注意ください。




MacからUDPでメッセージを送ってみる



それでは最後に、実際にMacからiPhoneへUDPソケットを送ってみましょう。
Macのターミナルを開いて下記のコマンドを実行します。これはUDPクライアントを立ち上げる処理になります。
nc -u 192.168.100.119 8888
この後に、何か送信したいメッセージを入力し、リターンを押せばiPhone画面にメッセージが表示されるはずです。