私のシステムでは、私はジャグルのTCPクライアントの束を持っていると私はちょっと混乱している[私の経験のほとんどはCで、したがって不安です] 。私はブーストASIOを使用して接続を管理しています。これらは私が持っている要素であるC++デザイン:複数のTCPクライアント、ブーストasioとオブザーバー
- A TCPStreamクラス:ブースト上に薄いラッパーASIO
- TCP上のプロトコルを実装するIPCプロトコルは、: は基本的に各メッセージはタイプと長さフィールド ので、私達ができるで始まりますストリームから個々のメッセージを読み込みます。
- 私は簡潔にするために、擬似C++のコードを書いています接続
を監視し、メッセージ
class TCPStream {
boost::asio::socket socket_;
public:
template <typename F>
void connect (F f)
{
socket_.connect(f);
}
template <typename F>
void read (F f)
{
socket_.read(f);
}
};
class IpcProtocol : public TCPStream {
public:
template <typename F
void read (F f)
{
TCPStream::read(
[f] (buffer, err) {
while (msg = read_indvidual_message(buffer)) {
// **** this is a violation of how this pattern is
// supposed to work. Ideally there should a callback
// for individual message. Here the same callback
// is called for N no. of messages. But in our case
// its the same callback everytime so this should be
// fine - just avoids some function calls.
f(msg);
};
};
)
}
};
私はTCPコネクションの束を持っていると、接続ごとにハンドラクラス があるとしましょうアイデアを得ると思います。名前をConnection1、Connection2 ...
class Connection {
virtual int type() = 0;
};
class Connection1 : public Connection {
shared_ptr<IpcProtocol> ipc_;
int type()
{
return 1;
}
void start()
{
ipc_.connect([self = shared_from_this()](){ self->connected(); });
ipc_.read(
[self = shared_from_this()](msg, err) {
if (!err)
self->process(msg);
} else {
self->error();
}
});
}
void connected()
{
observer.notify_connected(shared_from_this());
}
void error()
{
observer.notify_error(shared_from_this());
}
};
このパターンは、一方向などのすべての接続で繰り返されます。 メッセージは接続クラス自体によって処理されます。しかし、それは 他のイベント[接続、エラー]をオブザーバに知らせるでしょう。理由 -
- 再起動接続は、毎回それはみんなの
- バンチは、彼らが サーバーへの最初の要求/ confgurationを送ることができるように、接続が確立されるかどうかを知る必要があります切断します。
- muliple接続の接続ステータス 例:に基づいて行うことが必要なものがあります。接続1と接続2が確立されている場合は、connection3など
を開始私はミドルObserverクラスを追加したように、そこにオブザーバーであります再起動するたびに接続に直接接続する必要があります。接続が切断されるたびに、接続クラスが削除され、新しい接続クラスが作成されます。
class Listeners {
public:
virtual void notify_error(shared_ptr<Connection>) = 0;
virtual void notify_connect(shared_ptr<Connection>) = 0;
virtual void interested(int type) = 0;
};
class Observer {
std::vector<Listeners *> listeners_;
public:
void notify_connect(shared_ptr<Connection> connection)
{
for (listener : listeners_) {
if (listener->interested(connection->type())) {
listener->notify_error(connection);
}
}
}
};
ここでは、原型の試作品です。しかし、私はこのクラスのデザイン 良いかどうか疑問に思っていた。連続して状態を生成し、それを私のモジュールに送信して状態をh/wでプログラムする複数のストリーミングサーバがあります。これは将来的に多くのクライアントが追加されるため、拡張可能でなければなりません。レガシーコード
スレ
HTTPの例を見ると助けになりました。ポインタありがとう。生涯については。非同期補完ハンドラが呼び出されるまで、非同期操作を実行しているときには常に、shared-ptr自体が共有されます。あなたはこれに穴が見えますか? – MGH
はい@MGH私は穴、特にメモリとリソースのリークがあります。私はshared-ptrを所有する*サーバー*クライアントを好んでおり、 'non-amember'(または 'static')関数コールバックを使用して接続にweak-ptrを渡します。たとえば、接続クラス[here](https://github.com/kenba/via-httplib/tree/master/include/via/comms)を参照してください。 – kenba
私は 'class Connection'を見ました。私は何をしているのか分かりません。 1.共有ポインタを作成する静的 'create'ルーチンです。私はそのアイデアは接続を常に共有ポインタとして作成することを強制することだと思いますか? ( 'make()'の中でなぜ 'make_shared'が使われているのか分かりません) - 大丈夫です。しかし、私はクラスの関係を示す疑似コードです。詳細をスキップしました。 – MGH