www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Buffered Endian Stream Socket?

reply Kyle Mallory <jesuswasirish gmail.com> writes:
I'm trying to write a series of structs to a stream, which then has to 
be sent over the wire within a single TCP packet, in order for the host, 
an embedded device, to recognize the message.  If there is too little, 
or too much data for a given "command" (packet), the device will throw 
out the entire packet.  Ie, one packet must contain one complete message.

In all of my messages, the first 23 bytes are a common header.  I'm 
playing with having this header be a separate struct, apart from the 
subsequent payload struct.  This will allow me to do simple things like 
(in pseudo-d-code):

	msg.foo = 1234;
	msg.bar = "DMDD";
	hdr.datalen = Payload.sizeof;

	packet.write((&hdr)[0..1]);
	packet.write((&msg)[0..1]);
	socket.send(packet);

Since this is network data originating from various platforms, I also 
need to handle endian issues.

There are a few problems I'm running into with all of this:

I can't find a way to load data into a SocketStream without also issuing 
a Socket.send().  I considered a BufferedStream, or a MemoryStream but 
its not clear if/or how I would go about issuing an explicate send.  Is 
there a preferred way to do this that I'm missing?

Is is possible (or reasonable) to pass in arbitrary structs into 
EndianStream and expect that it will intelligently convert each type in 
the struct?
Apr 06 2010
parent Regan Heath <regan netmail.co.nz> writes:
Kyle Mallory wrote:
 I'm trying to write a series of structs to a stream, which then has to 
 be sent over the wire within a single TCP packet, in order for the host, 
 an embedded device, to recognize the message.  If there is too little, 
 or too much data for a given "command" (packet), the device will throw 
 out the entire packet.  Ie, one packet must contain one complete message.
 
 In all of my messages, the first 23 bytes are a common header.  I'm 
 playing with having this header be a separate struct, apart from the 
 subsequent payload struct.  This will allow me to do simple things like 
 (in pseudo-d-code):
 
     msg.foo = 1234;
     msg.bar = "DMDD";
     hdr.datalen = Payload.sizeof;
 
     packet.write((&hdr)[0..1]);
     packet.write((&msg)[0..1]);
     socket.send(packet);
 
 Since this is network data originating from various platforms, I also 
 need to handle endian issues.
 
 There are a few problems I'm running into with all of this:
 
 I can't find a way to load data into a SocketStream without also issuing 
 a Socket.send().  I considered a BufferedStream, or a MemoryStream but 
 its not clear if/or how I would go about issuing an explicate send.  Is 
 there a preferred way to do this that I'm missing?

If you had a BufferedStream wrapping a SocketStream, then I think you could call flush(); to trigger the send. It may depend on the size of the BufferedStream..
 Is is possible (or reasonable) to pass in arbitrary structs into 
 EndianStream and expect that it will intelligently convert each type in 
 the struct?

No.. I think you want to create your own PacketStream class containing an EndianStream, wrapping a BufferedStream, wrapping a SocketStream. Then.. all your structs you want to write derive from a common base struct and you implement a PacketStream.writeStruct(BaseStruct a) method which uses reflection to discover all the members of the struct at runtime. It would then call itself for all members derived from BaseStruct, and EndianStream.write for all basic types. Alternately, an easier/more verbose way to go is to have a seperate writeStruct specifically for each struct you want to write, and manually code them up to write all the members. This way means you have to remember to update them as you add members to structs etc. You'll need a member, or members in PacketStream to start and flush/send the packet. The former would write the packet header to the endian/buffer stream and the latter would call flush to send the data. R
Apr 21 2010