📢 Webサイト閉鎖と移転のお知らせ
このWebサイトは2026年9月に閉鎖いたします。
新しい記事は移転先で追加しております。(旧サイトでは記事を追加しておりません)
ページの作成:「== 概要 == librsyncライブラリは、ネットワーク効率的なファイル同期を実現するためのC言語ライブラリである。<br> Qtフレームワーク環境でもlibrsyncライブラリを使用することができ、効率的なデータ同期機能を実装する場合に役立つ。<br> <br> librsyncライブラリの主な特徴は、rsyncアルゴリズムを実装していることである。<br> このアルゴリズムにより、…」 |
|||
| (同じ利用者による、間の9版が非表示) | |||
| 26行目: | 26行目: | ||
librsyncライブラリはマルチスレッド環境での使用を想定していないため、Qtのマルチスレッド機能と併用する場合は注意が必要となる。<br> | librsyncライブラリはマルチスレッド環境での使用を想定していないため、Qtのマルチスレッド機能と併用する場合は注意が必要となる。<br> | ||
必要に応じて、ミューテックスやロック等の同期プリミティブを使用して、スレッドセーフな実装を行うことが重要である。<br> | 必要に応じて、ミューテックスやロック等の同期プリミティブを使用して、スレッドセーフな実装を行うことが重要である。<br> | ||
<br><br> | |||
== libRsyncのインストール == | |||
==== libRsyncの概要 ==== | |||
librsyncは、rsyncと同様、効率的にファイルを転送する他のプログラムを構築するためのものである。<br> | |||
バックアップおよびプログラムにバイナリパッチを配布したり、ディレクトリをサーバやピア間で同期するために記述したプログラムである。<br> | |||
<br> | |||
librsyncは、ネットワーク差分を計算し適用するためのライブラリであり、多様なネットワークソフトウェアに統合できるように設計されたインターフェイスを備えている。<br> | |||
<br> | |||
librsyncは、rsyncプロトコルのコアアルゴリズムをカプセル化して、2つのファイルの差分を効率的に計算するのに役立つ。<br> | |||
rsyncアルゴリズムは、差分を計算するために2つのファイルが存在する必要が無いため、ほとんどの差分アルゴリズムとは異なる。<br> | |||
<br> | |||
その代わり、一方のファイルの各ブロックのチェックサムのセットを必要とし、それらが一緒になってそのファイルの署名を形成する。<br> | |||
もう一方のファイルのどの位置のブロックでも、チェックサムが同じであれば、同一である可能性が高く、残ったものが差分となる。<br> | |||
<br> | |||
このアルゴリズムは、同じシステム上で両方のファイルを必要とすることなく、2つのファイル間の差分を転送する。<br> | |||
<br> | |||
librsyncは、元々、HTTPのデルタ圧縮におけるrproxy実験のために作成された。<br> | |||
現在では、Dropbox、rdiff-backup、Duplicity等で使用されている。<br> | |||
<br> | |||
<u>※注意</u><br> | |||
<u>librsyncライブラリは、rsyncワイヤプロトコルを実装していない。</u><br> | |||
<u>ファイルを転送するためにrsyncサーバと対話する場合は、rsyncにシェルアウトする必要がある。</u><br> | |||
<br> | |||
<u>librsyncライブラリは、ファイル名、パーミッション、ディレクトリ等のファイルのメタデータや構造を扱わない。</u><br> | |||
<u>このライブラリにとって、ファイルは単なるバイトのストリームである。</u><br> | |||
<br> | |||
<u>librsyncライブラリは、SSHやその他のサーバと通信するためのネットワーク関数も含まれていない。</u><br> | |||
<u>そのため、リモートファイルシステムにアクセスするには、独自のコードを提供する、または、他の仮想ファイルシステムレイヤーを使用する必要がある。</u><br> | |||
<br> | |||
<u>libRsyncライブラリのライセンスは、LGPL v2.1に準拠している。</u><br> | |||
<br> | |||
libRsyncライブラリの詳細な使用方法は、公式WebサイトまたはGithubを参照すること。<br> | |||
* 公式Webサイト : https://librsync.github.io/ | |||
<br> | |||
==== ソースコードからインストール ==== | |||
ビルドに必要な依存関係のライブラリをインストールする。<br> | |||
sudo zypper install libb2-devel | |||
<br> | |||
[https://github.com/librsync/librsync libRsyncのGitHub]からソースコードをダウンロードする。<br> | |||
ダウンロードしたファイルを解凍する。<br> | |||
tar xf librsync-<バージョン>.tar.gz | |||
cd librsync-<バージョン> | |||
<br> | |||
または、Githubからソースコードをクローンする。<br> | |||
git clone https://github.com/librsync/librsync.git | |||
cd librsync | |||
<br> | |||
libRsyncをビルドおよびインストールする。<br> | |||
mkdir build && cd build | |||
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=<libRsyncインストールディレクトリ> .. | |||
make -j $(nproc) | |||
make install | |||
<br> | |||
~/.profileファイル等に、環境変数を追記する。<br> | |||
vi ~/.profile | |||
<br> | |||
<syntaxhighlight lang="sh"> | |||
# ~/.profileファイル | |||
export PATH="/<libRsyncのインストールディレクトリ>/bin:$PATH" | |||
export LD_LIBRARY_PATH="/<libRsyncのインストールディレクトリ>/lib64:$LD_LIBRARY_PATH" | |||
</syntaxhighlight> | |||
<br> | |||
==== パッケージ管理システムからインストール ==== | |||
sudo zypper install librsync2 | |||
<br><br> | |||
== ライブラリのリンク == | |||
Pkg-configを使用してlibrsyncライブラリを検索して、プロジェクトにリンクする。<br> | |||
システムにPkg-configとlibrsyncライブラリがインストールされていることを確認すること。<br> | |||
<br> | |||
* Qtプロジェクトファイル (.pro) の場合 | |||
<syntaxhighlight lang="make"> | |||
# Pkg-configを使用 | |||
CONFIG += link_pkgconfig | |||
PKGCONFIG += librsync | |||
</syntaxhighlight> | |||
<br> | |||
* CMakeLists.txtファイルの場合 | |||
<syntaxhighlight lang="cmake"> | |||
# librsyncの依存関係を確認 | |||
pkg_check_modules(LIBRSYNC REQUIRED librsync) | |||
# 実行可能ファイルを追加 | |||
add_executable(<ターゲット名> | |||
main.cpp | |||
) | |||
# インクルードディレクトリを追加 | |||
target_include_directories(<ターゲット名> PRIVATE ${LIBRSYNC_INCLUDE_DIRS}) | |||
# リンクオプションを追加 (必要な場合) | |||
target_link_options(<ターゲット名> PRIVATE | |||
${LIBRSYNC_LDFLAGS} | |||
) | |||
# pkg_check_modulesコマンドがLIBRSYNC_LDFLAGSを提供していない場合や追加のカスタムフラグが必要な場合 | |||
#target_link_options(<ターゲット名> PRIVATE | |||
# "-L${LIBRSYNC_LIBRARY_DIRS}" | |||
#) | |||
# ライブラリをリンク | |||
target_link_libraries(<ターゲット名> PRIVATE | |||
${LIBRSYNC_LIBRARIES} | |||
) | |||
</syntaxhighlight> | |||
<br><br> | <br><br> | ||
== ローカルディレクトリとの同期 == | == ローカルディレクトリとの同期 == | ||
以下の例では、librsyncライブラリを使用して、同一PC上のファイルおよびディレクトリを非同期でファイルを差分転送している。<br> | |||
<br> | <br> | ||
* 非同期処理 | * 非同期処理 | ||
| 197行目: | 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]] | ||