How to use the streamer to send data over TCP not with ROOT

Ciao,
I am trying to develop a root application which sends/receives objects (mostly histos) via network. I know I could use TSocket::SendObject, but I havo to use a private TCP library to keep consistency with the framework we have. So what I need is roughly: the way to dump an object to a memory buffer, and the way to rebuild it on the other side from the buffer received. I guess this is roughly what SendObject does, but I could not find anywhere on the tutorial the methods for that.

Can someone help?

Thanks a lot

Tommaso

see example in class TMessage (derives from TBuffer) and the tutorials
hclient.C, hserv.C

Rene

Let me refine the problem: We want to stream a histogram into
a preallocated buffer. I managed to do this (though not sure if it’s
really correct):

int bins = 10;
int xmin = 0;
int xmax = 10;
TH1S* histogramU16_ = new TH1S (“histogramU16_”, “U16 data”, bins, xmin, xmax);
histogramU16_->SetBit (TH1::kCanRebin); // allow automatic rebinning

for (int i = 0; i < 10; i++) {
histogramU16_->Fill(i);
}

// Create a buffer
int size = 4096;
char* buffer = new char(size);
int offset = 64;

// Create a Root Buffer
TBuffer rootBuffer(TBuffer::kWrite, size, &buffer[offset], false);

// Stream histogram
histogramU16_->Streamer(rootBuffer);

As you can see, I would like to give a pre-allocated buffer to TBuffer,
indicating the real start of the writable memory by an offset. Everything
seems fine, but somehow we would need to find out, how big the
buffer should be before streaming. Alternatively, an exception/error
should be caught, if the streamer requires more than the provided memory.

Any hints to that?
Grateful Johannes

Hi Johanes,

What you do should work.
Concerning the exception handling in case
of buffer overflow, it is may simpler if you derive your own TBuffer class and redefine
the TBuffer::Expand function

One could may retrofit your implementation in the default version, once you have something working. Let me know.

Rene

I could make it working in a “stupid” way, just simulating a transmission over the wire. I simply put the object streamed output in a char*, and from that recreated another object: something like

TH1S* histogramU16_ = new TH1S (“histogramU16_”, “U16 data”, bins, xmin, xmax)
;

int size = 4096;
char buffer[size];
TBuffer rootBuffer(TBuffer::kWrite, size, buffer, true);
histogramU16_->Streamer(rootBuffer);

char * newb = buffer;// this simulates passing the
// memory buffer over the net
TH1S* newHist= new TH1S();
TBuffer rootBuffer2(TBuffer::kRead, size, newb, false);
newHist->Streamer(rootBuffer2);
newHist->Print();

It works… but still the size is passed as a parameter; it is the maximum size.

Hi,

have a look at this thread:

root.cern.ch/phpBB2/viewtopic.php?t=268

It describes a solution for your problem.

Cheers, Fons.

The proposed solutions will work nicely for receiving
the byte stream and re-production the original object.
As you’ve seen from my previous post, we need to stream
into a pre-allocated buffer at a certain offset.

Rene’s comment to overload the Expand() method seems
like an approach that we can use to make a prototype
running. It would however be advantageous to find out
the size of the object to be streamed in advance. I just
fear that this could be difficult. Help on this issue would
be greatly appreciated.

Thanks for your hints. We’ll go do some coding now :slight_smile:

Johannes

Ok, it was very helpful
The next example works perfectly.

I do not see problems with the size, since you can know about it before allocating the i2o buffer…

Tommaso

#include “TH1S.h”
#include “TMessage.h”
#include

class MyMessage : public TMessage {
public:
MyMessage(void buf, Int_t len) : TMessage(buf, len) { }
};
int main(){
int bins = 10;
int xmin = 0;
int xmax = 10;
TH1S
histogramU16_ = new TH1S (“histogramU16_”, “U16 data”, bins, xmin, xmax)
;
histogramU16_->SetBit (TH1::kCanRebin); // allow automatic rebinning
for (int i = 0; i < 10; i++) {
histogramU16_->Fill(i);
}
histogramU16_->Print();
TMessage* msg = new TMessage (kMESS_OBJECT);
msg->Reset();
msg->WriteObject (histogramU16_);

int j = (int)msg->Length();
cout <<" Created a Message "<<j<<endl;
char *k = msg->Buffer();
//
// this is what I send over network; on the recaiver side I see “received”
//
char received[j];
for(int oo=0;oo<j;oo++)
received[oo] = k[oo];

TMessage* msg2 = new MyMessage(received,j);
TH1S* newHist = (TH1S*) msg2->ReadObject(msg2->GetClass());

newHist->Print();
}