2012年08月21日

UDP Hole PunchingでNAT越えの実験をしてみた

昨日、AndyVisionWi-Fiを作ったよの記事を本ブログに書きました。
Andy自身でネットワークに繋がるなら、インターネット越しの遠隔制御したい、と思うところです。しかもカメラついてたら、楽しそうだし。。


さて、インターネットを介して複数の機器が連携したい場合、それぞれにグローバルIPが割当たっていれば特に問題なく通信はできるでしょうけれども、もし、それぞれの機器がルーターにぶら下がっているような場合、中継サーバなどを用いない場合、直接機器間で通信をどのように確立するか?という課題が発生します。

そこで、オールマイティな手法ではないようですが、大抵のルーター環境で使えそうなのが、UDP Hole Punchingという手法ということのようです。
この手法を使用すると、たとえばルーターAに繋がった機器aとルーターBに繋がった機器b同士が、ダイレクトにUDP通信できる、ということでした。いわゆる「NAT越え」の手法の一つだそうです。

UDPホールパンチングの何故UDPのパケットをダイレクトに機器間でやりとりできるか?の理屈は、ググるといろいろ出てきますので端折るとして、実際にコードを作成し、パケットを送受信させてみて、どんな感じか実験してみることにします。

ネットワークA : イーモバのポケットルーターに繋がってるPC1
ネットワークB : 光回線+バッファロールーターに繋がってるPC2
PC1とPC2とでUDPで直接お話し出来してみる、という実験です。

とりあえず、Rubyにて、実験用のコードを作ってみます。

PC1で1st.rb <ネットワークBのグローバルIP>として起動します。
次に、PC2で2nd.rb <ネットワークAのグローバルIP>として起動します。

すると、1st.rb側で既に開いてる穴に向かって2nd.rbからのUDPパケットが到着します。
1st.rb側は、2nd.rbからのUDPパケットの送信元情報を使用して、2nd.rb側に
パケットを投げますと、同様に2nd.rb実行側にも穴が開いてるのでパケットが届きます。

というわけで、いとも簡単にNAT越えできちゃいました!
実際に複数の機器間通信をやりたい時には、接続相手の管理をインターネット上の別サーバに行わせた上で、機器同士が通信をはじめれば良いのでしょうね。

1st.rb
#!/usr/bin/ruby

require "socket"

ipaddr = ARGV[0]
port = 25000

printf("Accessing to %s:%d...",ipaddr,port)
STDOUT.flush

udp = UDPSocket.open()
sockaddr = Socket.pack_sockaddr_in(port,ipaddr)
udp.bind("0.0.0.0",port)

udp.send("Hello",0,sockaddr)

count = 0

msg,inet_addr = udp.recvfrom(65535)
printf("Packet received.message=[%s]\n",msg)
p inet_addr

sockaddr2 = Socket.pack_sockaddr_in(port,inet_addr[3])

while(true)
  udp.send(sprintf("Send from 1st.rb:Count %8d\n",count),0,sockaddr2)
  count += 1
  sleep(0.5)
  p udp.recv(65535)
end

udp.close
2nd.rb
#!/usr/bin/ruby

require "socket"

ipaddr = ARGV[0]
port = 25000

udp = UDPSocket.open()
sockaddr = Socket.pack_sockaddr_in(port,ipaddr)
udp.bind("0.0.0.0",port)

udp.send("Hello",0,sockaddr)

count = 50000

while(true)
  udp.send(sprintf("Send from 2nd.rb:Count %8d\n",count),0,sockaddr)
  count += 1
  p udp.recv(65535)
end

udp.close
リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)
Dustin Boswell Trevor Foucher
オライリージャパン
売り上げランキング: 325

たのしいRuby 第3版
たのしいRuby 第3版
posted with amazlet at 12.08.21
高橋 征義 後藤 裕蔵
ソフトバンククリエイティブ
売り上げランキング: 6858
posted by いしいっち at 23:30| Comment(0) | TrackBack(0) | コンピュータ | このブログの読者になる | 更新情報をチェックする

カメラ付き&WiFi制御Android制御対応ラジコン AndyVisionWi-Fi作ってみた

久々のAndyくんいじりです。Andyってのは、Bluetooth経由で制御できるAndroid端末用のラジコンの事です。

先日、盆休みに実家に数日帰省していたので、昼間は出かけたりしてましたが、夜はもくもくとハンダ付けしたりして遊んでました。その時に作っていたものです。
実家ではする事があまりなくて、集中できるんですよね。。。

春先にGoodLuckBuyで購入したCMOSカメラ(ちょっと部品配置が違うような気がするものの、トラ技で取り上げられていたカメラと同等の模様)を買ったもので、お試し的に制御を実装してみました。XBee Wi-Fiも買ったものの、メキシコにも持っていったのですがずっと使わずに転がっていたので使用することにして、Wi-Fi接続+カメラ搭載Andyを作ってみました。現在はTransparentモードなのであまり細かい制御は出来ません。

IMG_20120821_003837.jpg

カメラはサーボで方向が変わるように、と思いましたが、ラジコン台車に乗せたので特にその必要性は無くなりました。
カメラとの接続部分の図。。ぐにゃぐにゃのポリウレタン線です。かっこ良く並行直角で配線できたら良いんですけど。。。
IMG_20120821_003855.jpg

XBee Wi-Fiを使用しているので、AndroidのWi-Fiで接続します。
Android側のアプリを起動すると、ラジコン上のカメラのプレビュー画が出て、フレームレートは高くないものの逐次更新します。
カメラ画はSurfaceView、操作部はViewで書きましたー。
AndyVisionWiFi_SS.png

実は作って、動かして、遊んでて結構楽しめました^^;
Wi-Fiということもあり、結構遠隔操作も出来るというのもありまして、違う部屋の探検とか。。。^^;

で、楽しいのでもう少し深くやっていこうと思いまして、今後の目標は・・・
・バラックをもうちょっとマシな感じに(外観の見た目の向上)
・XBee Wi-Fiとの接続をUART→SPI化(カメラフレームレートの向上)
・カメラアクセスをマイコンの外部バスI/F経由にする(カメラフレームレートの向上)
・XBee Wi-Fiとの接続をAPIモードで(UDPホールパンチングのNAT超えを実装)
・NFC経由で接続情報をAndroid端末に上げるように(接続を簡便に)
とかを考えています。近いうちに出来たらいいなぁ。

ソースとかは整理してます。githubにアップしたいなーと思ってます。
(でも毎回、gitのガイドのサイトを見ないとろくに使用できない^^;)



XBee WiFi / ワイヤアンテナ型
スイッチサイエンス
売り上げランキング: 158198

posted by いしいっち at 01:08| Comment(2) | TrackBack(0) | 電子工作 | このブログの読者になる | 更新情報をチェックする