📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)

 
(同じ利用者による、間の7版が非表示)
84行目: 84行目:
  vi ~/.profile
  vi ~/.profile
<br>
<br>
<syntaxhighlight lang="sh">
  # ~/.profileファイル
  # ~/.profileファイル
   
   
  export PATH="/<libRsyncのインストールディレクトリ>/bin:$PATH"
  export PATH="/<libRsyncのインストールディレクトリ>/bin:$PATH"
  export LD_LIBRARY_PATH="/<libRsyncのインストールディレクトリ>/lib64:$LD_LIBRARY_PATH"
  export LD_LIBRARY_PATH="/<libRsyncのインストールディレクトリ>/lib64:$LD_LIBRARY_PATH"
</syntaxhighlight>
<br>
<br>
==== パッケージ管理システムからインストール ====
==== パッケージ管理システムからインストール ====
  sudo zypper install librsync2
  sudo zypper install librsync2
135行目: 138行目:


== ローカルディレクトリとの同期 ==
== ローカルディレクトリとの同期 ==
以下の例では、librsyncライブラリを使用して、ファイルおよびディレクトリを非同期でファイルを差分転送している。<br>
以下の例では、librsyncライブラリを使用して、同一PC上のファイルおよびディレクトリを非同期でファイルを差分転送している。<br>
<br>
<br>
* 非同期処理
* 非同期処理
303行目: 306行目:
<br><br>
<br><br>


== リモートPCのディレクトリとの同期 ==
==== 同期元 ====
以下の例では、librsyncライブラリを使用して、リモートPC上のファイルおよびディレクトリを非同期でファイルを差分転送している。<br>
<br>
* 非同期処理
*: QtConcurrent::runメソッドを実行して、ファイル同期を非同期で実行する。
*: QFutureクラスを使用して、非同期処理の結果を管理する。
* ネットワーク通信
*: QTcpSocketクラスを使用して、リモートホストと通信する。
* ストリーミング処理
*: ファイルデータとコマンドをストリーミングで送受信する。
* ディレクトリ構造の維持
*: ソースディレクトリの構造を宛先ディレクトリに複製する。
<br>
<syntaxhighlight lang="c++">
// RemoteFileSyncWorker.hファイル
#include <QObject>
#include <QDir>
#include <QDirIterator>
#include <QFileInfo>
#include <QDataStream>
#include <QFuture>
#include <QtConcurrent>
#include <QTcpSocket>
#include <librsync.h>
class RemoteFileSyncWorker : public QObject
{
    Q_OBJECT
private:
    QTcpSocket *socket;
    void syncFile(const QString &sourcePath, const QString &destPath)
    {
      QFile sourceFile(sourcePath);
      if (!sourceFile.open(QIODevice::ReadOnly)) {
          emit errorOccurred(QString("ソースファイルのオープンに失敗: %1").arg(sourcePath));
          return;
      }
      // リモートファイルのシグネチャを要求
      QByteArray command = "SIGNATURE:" + destPath.toUtf8();
      if (!sendData(command)) {
          emit errorOccurred("シグネチャ要求の送信に失敗");
          return;
      }
      QByteArray remoteSignature = receiveData();
      if (remoteSignature.isEmpty()) {
          emit errorOccurred("リモートシグネチャの受信に失敗");
          return;
      }
      // デルタの計算
      rs_result result;
      rs_buffers_t buf;
      char inbuf[8192];
      char outbuf[8192];
      rs_job_t *job = rs_delta_begin(new rs_signature_t());
      if (!job) {
          emit errorOccurred("デルタジョブの作成に失敗");
          return;
      }
      do {
          buf.next_in  = inbuf;
          buf.avail_in  = sourceFile.read(inbuf, sizeof(inbuf));
          buf.next_out  = outbuf;
          buf.avail_out = sizeof(outbuf);
          result = rs_job_iter(job, &buf);
          if (buf.avail_out < sizeof(outbuf)) {
            QByteArray deltaData(outbuf, sizeof(outbuf) - buf.avail_out);
            if (!sendData(deltaData)) {
                emit errorOccurred("デルタデータの送信に失敗");
                rs_job_free(job);
                return;
            }
          }
      } while (result == RS_BLOCKED);
      rs_job_free(job);
      if (result != RS_DONE) {
          emit errorOccurred(QString("デルタの計算に失敗しました: %1").arg(rs_strerror(result)));
          return;
      }
      // 完了通知
      if (!sendData("DONE")) {
          emit errorOccurred("完了通知の送信に失敗");
          return;
      }
      emit progressUpdated(1);
    }
    bool connectToHost(const QString &host, quint16 port)
    {
      socket->connectToHost(host, port);
      return socket->waitForConnected(5000);
    }
    void disconnectFromHost()
    {
      if (socket->state() == QAbstractSocket::ConnectedState) {
          socket->disconnectFromHost();
      }
    }
    bool sendData(const QByteArray &data)
    {
      QDataStream out(socket);
      out << quint32(data.size());
      out.writeRawData(data.constData(), data.size());
      return socket->waitForBytesWritten(5000);
  }
    QByteArray receiveData()
    {
      if (!socket->waitForReadyRead(5000)) {
          return QByteArray();
      }
      QDataStream in(socket);
      quint32 blockSize;
      in >> blockSize;
      while (socket->bytesAvailable() < blockSize) {
          if (!socket->waitForReadyRead(5000)) {
            return QByteArray();
          }
      }
      QByteArray data;
      data.resize(blockSize);
      in.readRawData(data.data(), blockSize);
      return data;
    }
public:
    explicit RemoteFileSyncWorker(QObject *parent = nullptr) : QObject(parent), socket(new QTcpSocket(this))
    {}
    ~RemoteFileSyncWorker()
    {
      disconnectFromHost();
    }
    QFuture<void> syncFiles(const QString &sourcePath, const QString &destPath, const QString &host, quint16 port)
    {
      return QtConcurrent::run([this, sourcePath, destPath, host, port]() {
          if (!connectToHost(host, port)) {
            emit errorOccurred("リモートホストへの接続に失敗しました");
            return;
          }
          QDirIterator it(sourcePath, QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
          while (it.hasNext()) {
            QString sourceFilePath = it.next();
            QString relativeFilePath = QDir(sourcePath).relativeFilePath(sourceFilePath);
            QString destFilePath = QDir(destPath).filePath(relativeFilePath);
            QFileInfo sourceInfo(sourceFilePath);
            if (sourceInfo.isDir()) {
                // リモートPCでディレクトリを作成するコマンドを送信
                QByteArray command = "MKDIR:" + destFilePath.toUtf8();
                if (!sendData(command)) {
                  emit errorOccurred("ディレクトリ作成コマンドの送信に失敗");
                  return;
                }
            }
            else {
                syncFile(sourceFilePath, destFilePath);
            }
          }
          disconnectFromHost();
      });
    }
signals:
    void progressUpdated(int progress);
    void errorOccurred(const QString &error);
};
#endif // REMOTEFILESYNCWORKER_H
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
#include <QCoreApplication>
#include <QDebug>
#include "RemoteFileSyncWorker.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    QString sourcePath = "<同期元ディレクトリ>";
    QString destPath  = "<同期先ディレクトリ>";
    QString remoteHost = "<リモートホストのIPアドレス>";
    quint16 remotePort = <リモートホストのポート番号>;
    RemoteFileSyncWorker worker;
    QObject::connect(&worker, &RemoteFileSyncWorker::progressUpdated, [](int progress) {
      qDebug() << "進捗: " << progress;
    });
    QObject::connect(&worker, &RemoteFileSyncWorker::errorOccurred, [](const QString &error) {
      qDebug() << "エラー: " << error;
    });
    // 同期の開始
    QFuture<void> future = worker.syncFiles(sourcePath, destPath, remoteHost, remotePort);
    // メインイベントループを開始
    int result = a.exec();
    // 同期完了まで待機
    future.waitForFinished();
    return result;
}
</syntaxhighlight>
<br>
==== 同期先 (リモートPC) ====
以下の例では、librsyncライブラリを使用して、同期元から転送されたファイルおよびディレクトリを非同期で受信している。<br>
<br>
* 非同期処理
*: QtConcurrentクラスを使用して、コマンド処理やデータ送信を非同期で行う。
*: QTcpServerクラスおよびQTcpSocketクラスを使用して、非同期のネットワーク通信を実現している。
* ストリーミング処理
*: クライアントからのデータを段階的に読み取る。
*: 大きなファイルやデータの場合でも効率的に処理できる。
* librsyncライブラリの使用
*: librsyncライブラリを使用して、効率的なファイル同期を実現している。
*: ファイルのシグネチャ生成やデルタの適用等の処理を行う。
<br>
<syntaxhighlight lang="c++">
  // RemoteSyncServer.hファイル
#include <QObject>
#include <QFile>
#include <QDataStream>
#include <QDir>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFuture>
#include <QtConcurrent>
#include <librsync.h>
class RemoteSyncServer : public QObject
{
    Q_OBJECT
private:
    QTcpServer                    *server;
    QMap<QTcpSocket*, QByteArray> clientBuffers;
    // クライアントからのコマンドを処理
    void processCommand(QTcpSocket *client, const QByteArray &command)
    {
      if (command.startsWith("MKDIR:")) {
          // ディレクトリ作成コマンドを処理
          QString path = QString::fromUtf8(command.mid(6));
          createDirectory(client, path);
      }
      else if (command.startsWith("SIGNATURE:")) {
          // シグネチャ要求コマンドを処理
          QString path = QString::fromUtf8(command.mid(10));
          sendFileSignature(client, path);
      }
      else if (command == "DONE") {
          // 完了通知を処理する場合
      }
      else {
          // 不明なコマンドの場合はデルタデータとして処理
          QString path = client->property("currentFile").toString();
          if (!path.isEmpty()) {
            applyDelta(client, path, command);
          }
          else {
            sendError(client, "不明なコマンドまたは無効なデルタデータ");
          }
      }
    }
    // ディレクトリを作成
    void createDirectory(QTcpSocket *client, const QString &path)
    {
      QDir dir;
      if (!dir.mkpath(path)) {
          sendError(client, QString("ディレクトリの作成に失敗: %1").arg(path));
      }
    }
    // ファイルのシグネチャを送信
    void sendFileSignature(QTcpSocket *client, const QString &path)
    {
      QFile file(path);
      if (!file.open(QIODevice::ReadOnly)) {
          sendError(client, QString("ファイルのオープンに失敗: %1").arg(path));
          return;
      }
      // librsyncを使用してシグネチャを生成
      rs_result result;
      rs_signature_t *sig;
      FILE *f = fdopen(file.handle(), "rb");
      result = rs_sig_file(f, &sig, RS_DEFAULT_BLOCK_LEN, 0, RS_MD4_SIG_MAGIC);
      if (result != RS_DONE) {
          sendError(client, QString("シグネチャの生成に失敗: %1").arg(rs_strerror(result)));
          return;
      }
      // シグネチャをバイト配列に変換
      rs_buffers_t buf;
      char        outbuf[8192];
      QByteArray  signature;
      buf.next_out = outbuf;
      buf.avail_out = sizeof(outbuf);
      do {
          result = rs_job_iter(sig, &buf);
          if (buf.avail_out < sizeof(outbuf)) {
            signature.append(outbuf, sizeof(outbuf) - buf.avail_out);
            buf.next_out = outbuf;
            buf.avail_out = sizeof(outbuf);
          }
      } while (result == RS_BLOCKED);
      rs_job_free(sig);
      if (result != RS_DONE) {
          sendError(client, QString("シグネチャの変換に失敗: %1").arg(rs_strerror(result)));
          return;
      }
      // シグネチャを非同期で送信
      sendDataAsync(client, signature);
      client->setProperty("currentFile", path);
    }
    // デルタを適用してファイルを更新
    void applyDelta(QTcpSocket *client, const QString &path, const QByteArray &deltaData)
    {
      QFile file(path);
      if (!file.open(QIODevice::ReadWrite)) {
          sendError(client, QString("ファイルのオープンに失敗: %1").arg(path));
          return;
      }
      // librsyncを使用してデルタを適用
      rs_result result;
      FILE *basis_file = fdopen(file.handle(), "r+b");
      rs_signature_t *sig = nullptr;
      // シグネチャの再構築
      result = rs_sig_file(basis_file, &sig, RS_DEFAULT_BLOCK_LEN, 0, RS_MD4_SIG_MAGIC);
      if (result != RS_DONE) {
          sendError(client, QString("シグネチャの再構築に失敗: %1").arg(rs_strerror(result)));
          return;
      }
      // 一時ファイルの作成
      QTemporaryFile newFile;
      if (!newFile.open()) {
          sendError(client, "一時ファイルの作成に失敗");
          rs_free_sumset(sig);
          return;
      }
      FILE *new_file = fdopen(newFile.handle(), "w+b");
      // デルタの適用
      rs_buffers_t buf;
      char inbuf[8192];
      char outbuf[8192];
      buf.next_in = deltaData.constData();
      buf.avail_in = deltaData.size();
      buf.next_out = outbuf;
      buf.avail_out = sizeof(outbuf);
      rs_job_t *job = rs_patch_begin(rs_file_copy_cb, basis_file);
      do {
          result = rs_job_iter(job, &buf);
          if (buf.avail_out < sizeof(outbuf)) {
            size_t written = fwrite(outbuf, 1, sizeof(outbuf) - buf.avail_out, new_file);
            if (written != sizeof(outbuf) - buf.avail_out) {
                sendError(client, "一時ファイルへの書き込みに失敗");
                rs_job_free(job);
                rs_free_sumset(sig);
                return;
            }
            buf.next_out = outbuf;
            buf.avail_out = sizeof(outbuf);
          }
      } while (result == RS_BLOCKED);
      rs_job_free(job);
      rs_free_sumset(sig);
 
      if (result != RS_DONE) {
          sendError(client, QString("デルタの適用に失敗: %1").arg(rs_strerror(result)));
          return;
      }
      // 一時ファイルを元のファイルに上書き
      file.close();
      newFile.close();
      if (!QFile::remove(path) || !newFile.rename(path)) {
          sendError(client, "ファイルの更新に失敗");
          return;
      }
      // 成功メッセージを送信
      sendDataAsync(client, "SUCCESS");
    }
    // データを非同期で送信する
    QFuture<void> sendDataAsync(QTcpSocket *client, const QByteArray &data)
    {
      return QtConcurrent::run([client, data]() {
          QDataStream out(client);
          out << quint32(data.size());
          out.writeRawData(data.constData(), data.size());
          client->waitForBytesWritten();
      });
    }
    // エラーメッセージをクライアントに送信する
    void sendError(QTcpSocket *client, const QString &error)
    {
      QByteArray errorData = QString("ERROR:%1").arg(error).toUtf8();
      sendDataAsync(client, errorData);
      emit errorOccurred(error);
    }
public:
    explicit RemoteSyncServer(QObject *parent) : QObject(parent), server(new QTcpServer(this))
    {
      // サーバーの新しい接続シグナルをhandleNewConnectionスロットに接続
      connect(server, &QTcpServer::newConnection, this, &RemoteSyncServer::handleNewConnection);
    }
    ~RemoteSyncServer()
    {
      // サーバが稼働中の場合は停止
      if (server->isListening()) {
          server->close();
      }
    }
    // サーバを指定されたポートで開始
    bool start(quint16 port)
    {
      // 指定されたポートでサーバーを開始
      if (!server->listen(QHostAddress::Any, port)) {
          emit errorOccurred(QString("サーバの起動に失敗: %1").arg(server->errorString()));
          return false;
      }
      return true;
    }
signals:
    // エラー発生時に発行されるシグナル
    void errorOccurred(const QString &error);
private slots:
    // 新しいクライアント接続を処理
    void handleNewConnection()
    {
      // 新しいクライアント接続を取得
      QTcpSocket *clientSocket = server->nextPendingConnection();
      // クライアントのreadyRead信号をreadClientDataスロットに接続
      connect(clientSocket, &QTcpSocket::readyRead, this, &RemoteSyncServer::readClientData);
      // クライアントの切断を処理
      connect(clientSocket, &QTcpSocket::disconnected, [this, clientSocket]() {
          clientBuffers.remove(clientSocket);
          clientSocket->deleteLater();
      });
    }
    // クライアントからのデータを読み取るスロット
    void readClientData()
    {
      // シグナルを送信したクライアントソケットを取得
      QTcpSocket *clientSocket = qobject_cast<QTcpSocket*>(sender());
      if (!clientSocket) return;
      // クライアントからのデータを読み取り
      QByteArray &buffer = clientBuffers[clientSocket];
      buffer.append(clientSocket->readAll());
      // 完全なコマンドを処理
      while (buffer.size() >= 4) {
          QDataStream stream(buffer);
          quint32 size;
          stream >> size;
          if (buffer.size() < size + 4) break;
          QByteArray command = buffer.mid(4, size);
          buffer.remove(0, size + 4);
          // コマンドを非同期で処理
          QtConcurrent::run([this, clientSocket, command]() {
            processCommand(clientSocket, command);
          });
    }
};
</syntaxhighlight>
<br>
<syntaxhighlight lang="c++">
// main.cppファイル
#include "RemoteSyncServer.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    qint16 port = <ポート番号>;
    RemoteSyncServer server;
    if (!server.start(port)) {
      qDebug() << "サーバの起動に失敗";
      return -1;
    }
    qDebug() << QString("サーバが起動 (ポート: %1")).arg(port);
    return a.exec();
}
</syntaxhighlight>
<br><br>
{{#seo:
|title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki
|keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板
|description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux
|image=/resources/assets/MochiuLogo_Single_Blue.png
}}


__FORCETOC__
__FORCETOC__
[[カテゴリ:Qt]]
[[カテゴリ:Qt]]