2012年3月1日木曜日

( Qt C++ )QUdpSocketを使用する。


はい、それでは表題の件やっていきます。
サンプルはC++ GUI Programming with Qt4のものは長すぎなので、独自のものを使用します。

いつものようにQtCreaterの使用を前提とします。(QtCreaterなどの使い方は ”Qtをはじめよう" を見てください。)

また.proファイルに QT += network を必ず追加してください。(でなければ動きません。)

ではコードを


(mainwindow.h)
#include <QMainWindow>
#include <QUdpSocket>
#include <QDataStream>
#include <QByteArray>
#include <QDateTime>
#include <QMessageBox>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

protected slots:
    void sendDatagram();
    void processPendingDatagram();
    void showMessage();

private:
    Ui::MainWindow *ui;
    QUdpSocket udpsocket1;//送信側
    QUdpSocket udpsocket2;//受信側
    QString message;
};


(mainwindow.cpp)
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    udpsocket2.bind(5824);
    connect(ui->pushButton, SIGNAL(clicked()),  this, SLOT(sendDatagram()));
    connect(ui->pushButton_2, SIGNAL(clicked()),  this, SLOT(showMessage()));
    connect(&udpsocket2, SIGNAL(readyRead()), this, SLOT(processPendingDatagram()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::sendDatagram()
{
    QByteArray datagram;
    QDataStream out(&datagram, QIODevice::WriteOnly);
    out.setVersion(QDataStream::Qt_4_1);
    out << QDateTime::currentDateTime() ;

    udpsocket1.writeDatagram(datagram, QHostAddress::LocalHost, 5824);
}

void MainWindow::processPendingDatagram()
{
    QByteArray datagram;

    do
    {
        datagram.resize(udpsocket2.pendingDatagramSize());
        udpsocket2.readDatagram(datagram.data(), datagram.size());
    }
    while (udpsocket2.hasPendingDatagrams());

    QDateTime dateTime;

    QDataStream in(&datagram, QIODevice::ReadOnly);
    in.setVersion(QDataStream::Qt_4_1);
    in >> dateTime;

    message = dateTime.time().toString();
}

void MainWindow::showMessage()
{
    ui->label->setText(message);
}

はい簡単ですね。(Mainwindowにはあらかじめボタン2つとラベルを1つ配置しておいてください。)ヘッダ部はコメントのとおりです。説明はしません。

.cppは説明します。
まずはコンストラクタです。
受信用のudpsocket2のbindで受信を開始します。ポートは5824です。その後各シグナルを接続しています。これは見てのとおりですので説明省略します。

次のデストラクタは省略。

次にsendDatagram()です。
これは送信用のプッシュボタンのclicked()シグナルに対応して呼ばれるスロットです。コンストラクタでconnectしましたね。ここではただ単に現在の時間(QDateTime)をlocalhostのポート5824に送信しています。

次にprocessPendingDatagram()です。これはudpsocket2のreadyRead()シグナルに対応して呼ばれるスロットです。すなわちデータを受信すると呼ばれるということです。これもコンストラクタでconnectしましたね。ここでは受け取ったデータをQDateTimeとして取り出し、メンバのmessageに時刻を格納しています。ちなみにhasPendingDatagrams()はtrueの場合は少なくとも一つ以上の読込待ちがあることを指し、falseは全て読み込んだこと、あるいは読み込んでいない状態を指します。

最後にshowMessage()です。
これは状態表示用のプッシュボタンのclicked()シグナルに対応して呼ばれるスロットです。これもコンストラクタでconnectしましたね。これはただメンバのmessageをラベルにsetTextでセットしているだけです。

(QUdpSocket リファレンス

実行すると以下のようになります。

(初期状態)

(UDP送信ボタンを押した後、状態表示ボタンを押した時の画像)

以上です。