Yazılım mimarisinde model: Reactor modeli

Adanali

Active member
Yazılım mimarisinde model: Reactor modeli


  1. Yazılım mimarisinde model: Reactor modeli

Modeller, modern yazılım geliştirme ve yazılım mimarisinde önemli bir soyutlamadır. İyi tanımlanmış terminoloji, açık belgeler sunar ve en iyisinden öğrenirler. Sunucular veya GUI’ler gibi olay odaklı uygulamalar genellikle Reactor mimari modelini kullanır. Bu, aynı anda birden çok isteği kabul edebilir ve bunları farklı işleyicilere dağıtabilir.







Rainer Grimm, uzun yıllardır yazılım mimarı, ekip lideri ve eğitim yöneticisi olarak çalışmaktadır. C++, Python ve Haskell programlama dilleri üzerine makaleler yazmaktan hoşlanır, aynı zamanda sık sık uzmanlık konferanslarında konuşmaktan da keyif alır. Modernes C++ blogunda yoğun bir şekilde C++ tutkusundan bahsediyor.













Reactor modeli, çoğullamayı çözmek ve hizmet isteklerini aynı anda birden çok hizmet sağlayıcıya dağıtmak için olay güdümlü bir çerçevedir. İstekler senkronize olarak işlenir.

reaktör

Ayrıca şöyle bilinir

sorun



Bir sunucu

  • Aynı anda birden fazla müşteri talebine cevap vermek,
  • performanslı, istikrarlı ve ölçeklenebilir olun
  • yeni veya iyileştirilmiş hizmetleri desteklemek için genişletilebilir olmalıdır.
Uygulama, çoklu kullanım ve senkronizasyon sorunlarından korunmalıdır.

Çözüm

  • Desteklenen her hizmet bir yönetici içinde kapsüllenir.
  • İşleyiciler reaktörde kayıtlıdır.
  • Reaktör, gelen tüm olayları eşzamanlı olarak beklemek için bir olay çoğullama çözücü kullanır.
  • Reaktör bilgilendirildiğinde servis talebini ilgili yöneticiye iletir.
yapı














Handles

  • Tutamaçlar, ağ bağlantıları, açık dosyalar veya GUI olayları gibi çeşitli olay kaynaklarını tanımlar.
  • Olay kaynağı, ilişkili tanıtıcıda kuyruğa alınan bağlanma, okuma veya yazma gibi olaylar oluşturur.
Synchonous Event Demultiplexer

  • Eşzamanlı olay çoğullama çözücü, bir veya daha fazla bayrak olayını bekler ve ilgili tanıtıcı olayı işleyebilene kadar bloke eder.
  • Select, poll, epoll, kqueue veya WaitForMultipleObjects sistem çağrılarıyla gösterge olaylarını bekleyebilir.
Event Handler

  • Olay işleyici, gösterge olaylarını işlemek için arabirimi tanımlar.
  • Olay işleyici, uygulamanın desteklenen hizmetlerini tanımlar.
Concrete Event Handler

  • Somut olay işleyici, olay işleyici tarafından tanımlanan uygulama arayüzünü uygular.
Reactor

Reaktör

  • dosya tanımlayıcıları kullanarak somut olay işleyicisini kaydetmek ve kaydını silmek için bir arabirimi destekler,
  • gösterge olaylarını beklemek için bir senkronize olay çoğullama çözücü kullanır; bir gösterge olayı bir okuma, yazma veya hata olayı olabilir,
  • olayları somut olay işleyicilerine eşler e
  • olay döngüsünün süresini yönetir.
Reaktör (uygulama değil) bayrak olaylarının çoğullamayı çözmesini ve olayı göndermesini bekler. Somut olay işleyicileri reaktörde kayıtlıdır. Reaktör akış kontrolünü tersine çevirir. Kontrolün bu tersine çevrilmesi genellikle Hollywood İlkesi olarak adlandırılır.

Bir reaktörün dinamik davranışı oldukça ilginçtir.

dinamik davranış


Aşağıdaki noktalar, reaktör ile olay işleyici arasındaki kontrol akışını göstermektedir:

  • Uygulama, reaktördeki belirli olaylar için bir olay işleyicisi kaydeder.
  • Her olay işleyici, kendi özel işleyicisini reaktöre gösterir.
  • Uygulama olaylar döngüsünü başlatır. Olay döngüsü gösterge olaylarını bekler.
  • Bir olay kaynağı hazır olduğunda, olay çoğullama çözücüsü reaktöre geri döner.
  • Reaktör, tanıtıcıları uygun olay işleyiciye gönderir.
  • Olay işleyicisi olayı işler.
Reaktörü çalışırken görelim.

Örnek


Bu örnek, POCO çerçevesini kullanır. “POCO C++ Kitaplıkları, masaüstü bilgisayarlar, sunucular, mobil cihazlar, Nesnelerin İnterneti ve gömülü sistemler üzerinde çalışan ağ ve İnternet tabanlı uygulamalar oluşturmaya yönelik güçlü platformlar arası C++ kitaplıklarıdır.


// reactor.cpp

#include <fstream>
#include <string>

#include "Poco/Net/SocketReactor.h"
#include "Poco/Net/SocketAcceptor.h"
#include "Poco/Net/SocketNotification.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Observer.h"
#include "Poco/Thread.h"
#include "Poco/Util/ServerApplication.h"

using Poco::Observer;
using Poco::Thread;

using Poco::Net::ReadableNotification;
using Poco::Net::ServerSocket;
using Poco::Net::ShutdownNotification;
using Poco::Net::SocketAcceptor;
using Poco::Net::SocketReactor;
using Poco::Net::StreamSocket;

using Poco::Util::Application;

class EchoHandler {
public:
EchoHandler(const StreamSocket& s,
SocketReactor& r): socket(s), reactor(r) { // (11)
reactor.addEventHandler(socket,
Observer<EchoHandler, ReadableNotification>
(*this, &EchoHandler::socketReadable));
}

void socketReadable(ReadableNotification*) {
char buffer[8];
int n = socket.receiveBytes(buffer, sizeof(buffer));
if (n > 0) {
socket.sendBytes(buffer, n); // (13)
}
else {
reactor.removeEventHandler(socket, // (12)
Observer<EchoHandler,
ReadableNotification>
(*this, &EchoHandler::socketReadable));
delete this;
}
}

private:
StreamSocket socket;
SocketReactor& reactor;
};

class DataHandler {
public:

DataHandler(StreamSocket& s,
SocketReactor& r):
socket(s), reactor(r), outFile("reactorOutput.txt") {
reactor.addEventHandler(socket, // (14)
Observer<DataHandler,
ReadableNotification>
(*this, &DataHandler::socketReadable));
reactor.addEventHandler(socket, // (15)
Observer<DataHandler,
ShutdownNotification>
(*this, &DataHandler::socketShutdown));
socket.setBlocking(false);
}

~DataHandler() { // (16)
reactor.removeEventHandler(socket,
Observer<DataHandler,
ReadableNotification>
(*this, &DataHandler::socketReadable));
reactor.removeEventHandler(socket,
Observer<DataHandler,
ShutdownNotification>
(*this, &DataHandler::socketShutdown));
}

void socketReadable(ReadableNotification*) {
char buffer[64];
int n = 0;
do {
n = socket.receiveBytes(&buffer[0], sizeof(buffer));
if (n > 0) {
std::string s(buffer, n);
outFile << s << std::flush; // (17)
}
else break;
} while (true);
}

void socketShutdown(ShutdownNotification*) {
delete this;
}

private:
StreamSocket socket;
SocketReactor& reactor;
std::eek:fstream outFile;
};

class Server: public Poco::Util::ServerApplication {

protected:
void initialize(Application& self) { // (3)
ServerApplication::initialize(self);
}

void uninitialize() { // (4)
ServerApplication::uninitialize();
}

int main(const std::vector<std::string>&) { // (2)

ServerSocket serverSocketEcho(4711); // (5)
ServerSocket serverSocketData(4712); // (6)
SocketReactor reactor;
SocketAcceptor<EchoHandler>
acceptorEcho(serverSocketEcho, reactor); // (7)
SocketAcceptor<DataHandler>
acceptorData(serverSocketData, reactor); // (8)
Thread thread;
thread.start(reactor); // (9)
waitForTerminationRequest();
reactor.stop(); // (10)
thread.join();

return Application::EXIT_OK;

}

};

int main(int argc, char** argv) {

Server app; // (1)
return app.run(argc, argv);

}


(1) TCP sunucusunu oluşturun. Bu getiriyor mainişlev (2) ve (3)’te başlatılır ve (4)’te sıfırlanır. ONLAR main-TCP sunucu işlevi, 4711 5) ve 4712 (6) bağlantı noktalarını dinleyen iki sunucu soketi oluşturur. (7) ve (5)’te sunucu, dosyayla yuva yapar EchoHandler ve DataHandler oluşturuldu. ONLAR SocketAcceptor Alıcı-Bağlayıcı tasarım modelinin Alıcı bileşenini modeller. Reaktör, iptal talebini (10) alana kadar ayrı bir iş parçacığında (9) çalışır.

ONLAR EchoHandler yapıcıya (11) okuma tanıtıcısını kaydedin ve üye işlevindeki okuma tanıtıcısının kaydını kaldırın socketReadable (12) üzerinde. Müşteriden gelen mesajı döndürür (13). Tersine, DataHandler sunucuya veri iletmek için bir istemci. ONLAR Handler yapıcısında okuma olayları (14) ve kapatma olayları (satır 15) için eylemini kaydeder. İkisi birden Handler yok edici duruma gelmek DataHandler (16) tekrar abonelikten çıktı. Veri aktarımının sonucu doğrudan dosya tanıtıcısındadır outFile yazılı (17).

Aşağıdaki çıktı soldaki sunucuyu ve sağdaki iki istemciyi gösterir. Bir telnet oturumu istemci görevi görür. İlk istemci bağlantı noktasına bağlanır 4711: telnet 127.0.0.1 4711. Bu istemci yankı sunucusuna bağlanır ve ardından isteğini görüntüler. İkinci istemci 4712 numaralı bağlantı noktasına bağlanır: telnet 127.0.0.1 4712. Sunucudan gelen çıktı, istemci verilerinin sunucuya aktarıldığını gösterir.








Reaktörün artıları ve eksileri nelerdir?

Avantajlar ve dezavantajlar


Avantajlar

  • Çerçeve ve uygulama mantığı arasında açık bir ayrım.
  • Çeşitli somut olay yöneticilerinin modülerliği.
  • Select, poll, epoll, kqueue veya WaitForMultipleObjects gibi çoğullama çözme olaylarının altında yatan işlevler Unix (select, epoll) ve Windows (WaitForMultipleObjects) platformlarında mevcut olduğundan, reaktör farklı platformlara taşınabilir.
  • Arayüz ve uygulamanın ayrılması, hizmetlerin kolayca özelleştirilmesine veya genişletilmesine olanak tanır.
  • Genel mimari paralel yürütmeyi destekler.
Dezavantajları

  • Reaktör, olayların çoğullamasını çözmek için bir sistem çağrısı gerektirir.
  • Uzun süre çalışan bir olay işleyici, reaktörü engelleyebilir.
  • Kontrolün tersine çevrilmesi, test etmeyi ve hata ayıklamayı daha zor hale getirir.
Sıradaki ne?


Rekabet alanında kullanılan birçok kanıtlanmış model vardır. Paylaşım ve mutasyon gibi senkronizasyon sorunlarının yanı sıra rakip mimarilerle de ilgilenirler. Bir sonraki yazımda veri paylaşımına odaklanan şablonlarla başlayacağım.


(rm)



Haberin Sonu
 
Üst