需要のないページ

プログラミングや趣味や。

Qtでソケット通信を試してみた(UDP)

能書き

トランスポート層プロトコルは主に二種類ある。

  • 確実だけどめんどくさいTCP
  • 不確実だけど楽チンなUDP

今回はQtのQUdpSocketを用いたUDPのソケット通信を試してみた。

ネットワーク通信については詳述できないしないが、次のページが参考になる。

f:id:LouiS:20170324171137g:plain

 

また、QtのGUIの使い方は、以下のページで紹介したとおり。環境も同様。


ただし、モジュールの『Network』を有効にすること。

f:id:LouiS:20170324175701p:plain

 

サンプルコードの挙動

f:id:LouiS:20170324203640p:plain

Senderのエディットに文字列を入れてボタンを押すと、Recieverに反映される。

ただし、それぞれ別のアプリケーションとして起動する。それだけ。

 

このコードを実行するとき、このような警告が出ることがある。

両方のチェックボックスにチェックを入れて、アクセスを許可すること。

f:id:LouiS:20170324213759p:plain

 

サンプルコード―送信

送信用のウィジェットとして、次のようなものを用意する。

f:id:LouiS:20170324182843p:plain

clicked()シグナルと、ダイアログのsendDatagram()スロットを連結する。

 

まずヘッダファイル。

先のスロットと並んで、ソケットとポート番号を宣言している。

ポート番号は、ウェルノウン*1でなければ、適当に選んで大丈夫(だと思う)。 

ポート番号に関する解説は、このページが詳しい。

 

次に、ソースファイル。

23行目のwriteDatagram()第二引数には、通信先のIPアドレスを指定する。

  • QHostAddress::LocalHost
     自分自身と通信する、ループバックアドレス。実験段階で特に有用だろう。
  • QHostAddress::Broadcast
     同一ネットワーク上の全てのノードに送信するアドレス。ただし、ブロックするルータもある。
  • QHostAddress::QHostAddress( "xxx.xxx.xxx.xxx" )
     コンストラクタを用いて、IPv4アドレスを指定する方法。

 

18-21行目は、送信用のバイト列をうまく扱うための方便。

とりあえずは盲目に真似して、C++のストリームの恩恵に預かってよいだろう。

 

このように、送信側はただ『データを成形して』『送信する』だけで実装できる。

 

サンプルコード―受信側

受信側のウィジェットは単純で、ラベルが一つだけあるダイアログだ。

コードは次のとおり。

ヘッダファイルは送信側と酷似している。

ソースファイルに関しても、結局は『受信して』『データを解析して』いるだけ。

21行目から24行目は、このままでいろいろなニーズに使いまわせる。

 

受信側特有の処理は二つある。第一は、cppファイル9行目のbind()だ。

どのデータを受け取るか選ぶために、前もってポート番号を知らせる必要がある。

 

第二の特有の処理は、readyRead()シグナルと処理スロットを接続することだ。

サンプルコード10,11行目の処理にあたる。

readyRead()シグナルは、送信されたデータを読む準備が出来ると発呼される。 

 

まとめ

  • QUdpSocketクラスは、低信頼/高速の通信プロトコルを提供する。
  • 送信側/受信側が、共通のポート番号を知っておく必要がある。
  • 送受信にはQByteArrayクラスのバイト列を用いる。
    QDataStreamクラスを利用すると便利。
  • 受信側は、前もってbind処理を行っておくこと。
  • データが受信されると、readyRead()シグナルが発呼される。

案外単純である。

 

ストリームの取扱いに関しても、そのうち書く...かもしれない。

書かないかもしれない。 

 

ただし

ただし、このコードでは、短時間に連続して送られるデータには対応できない。

処理に手間取っているうちに送信されたデータは無視される。

全てのデータを扱う必要があるのなら、

hasPendingDatagrams()を用いたループ内に処理命令を書くこと。

リファレンスのサンプルコード片が参考になる。

 

これについてはそのうち書く。

*1:0~1023 予約されているポート