// Server program which allows clients, "spies", to connect and snoop objects. // To run this demo do the following: // - open two or more windows // - start root in all windows // - execute in the first window: .x spyserv.C (or spyserv.C++) // - execute in the other window(s): .x spy.C (or spy.C++) // - in the "spy" client windows click the "Connect" button and snoop // the histograms by clicking on the "hpx", "hpxpy" and "hprof" // buttons //Author: Fons Rademakers #include "TH1.h" #include "TH2.h" #include "TProfile.h" #include "TCanvas.h" #include "TFrame.h" #include "TSocket.h" #include "TServerSocket.h" #include "TMonitor.h" #include "TMessage.h" #include "TRandom.h" #include "TList.h" #ifndef __CINT__ #include "TError.h" #endif class SpyServ { private: TCanvas *fCanvas; // main canvas TH1F *fHpx; // 1-D histogram TH2F *fHpxpy; // 2-D histogram TProfile *fHprof; // profile histogram TServerSocket *fServ; // server socket TMonitor *fMon; // socket monitor TList *fSockets; // list of open spy sockets public: SpyServ(); ~SpyServ(); void HandleSocket(TSocket *s); }; void SpyServ::HandleSocket(TSocket *s) { if (s->IsA() == TServerSocket::Class()) { // accept new connection from spy TSocket *sock = ((TServerSocket*)s)->Accept(); fMon->Add(sock); fSockets->Add(sock); printf("accepted connection from %s\n", sock->GetInetAddress().GetHostName()); } else { // we only get string based requests from the spy char request[64]; if (s->Recv(request, sizeof(request)) <= 0) { fMon->Remove(s); fSockets->Remove(s); printf("closed connection from %s\n", s->GetInetAddress().GetHostName()); delete s; return; } // send requested object back TMessage answer(kMESS_OBJECT); if (!strcmp(request, "get hpx")) answer.WriteObject(fHpx); else if (!strcmp(request, "get hpxpy")) answer.WriteObject(fHpxpy); else if (!strcmp(request, "get hprof")) answer.WriteObject(fHprof); else Error("SpyServ::HandleSocket", "unexpected message"); s->Send(answer); } } SpyServ::SpyServ() { // Create the server process to fills a number of histograms. // A spy process can connect to it and ask for the histograms. // There is no apriory limit for the number of concurrent spy processes. // Open a server socket looking for connections on a named service or // on a specified port //TServerSocket *ss = new TServerSocket("spyserv", kTRUE); fServ = new TServerSocket(9090, kTRUE); if (!fServ->IsValid()) gSystem->Exit(1); // Add server socket to monitor so we are notified when a client needs to be // accepted fMon = new TMonitor; fMon->Add(fServ); // Create a list to contain all client connections fSockets = new TList; // Create a new canvas fCanvas = new TCanvas("SpyServ","SpyServ",200,10,700,500); fCanvas->SetFillColor(42); fCanvas->GetFrame()->SetFillColor(21); fCanvas->GetFrame()->SetBorderSize(6); fCanvas->GetFrame()->SetBorderMode(-1); // Create a 1-D, 2-D and a profile histogram fHpx = new TH1F("hpx","This is the px distribution",100,-4,4); fHpxpy = new TH2F("hpxpy","py vs px",40,-4,4,40,-4,4); fHprof = new TProfile("hprof","Profile of pz versus px",100,-4,4,0,20); // Set canvas/frame attributes (save old attributes) fHpx->SetFillColor(48); // Fill histograms randomly gRandom->SetSeed(); Float_t px, py, pz; const Int_t kUPDATE = 1000; for (Int_t i = 0; ; i++) { gRandom->Rannor(px,py); pz = px*px + py*py; fHpx->Fill(px); fHpxpy->Fill(px,py); fHprof->Fill(px,pz); if (i && (i%kUPDATE) == 0) { if (i == kUPDATE) fHpx->Draw(); fCanvas->Modified(); fCanvas->Update(); // Check if there is a message waiting on one of the sockets. // Wait not longer than 20ms (returns -1 in case of time-out). TSocket *s; if ((s = fMon->Select(20)) != (TSocket*)-1) HandleSocket(s); if (!fCanvas->TestBit(TObject::kNotDeleted)) break; if (gROOT->IsInterrupted()) break; } } } SpyServ::~SpyServ() { // Clean up fSockets->Delete(); delete fSockets; delete fServ; delete fCanvas; delete fHpx; delete fHpxpy; delete fHprof; } void spyserv() { new SpyServ; }