www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Sending a struct over TCP

reply SirErugor <ontherenth gmail.com> writes:
Hi there,

I've set up a server and a client application and I want to be able to send a
struct with fx. an integer and a char[]. So first I convert it to a ubyte[]
like this:

..
void write(T)(T input)
{
    buf ~= *(cast(ubyte[T.sizeof]*)&input)[0 .. T.sizeof];
}

Then I send the ubyte[] over through TCP via a SocketStream. On the client-side
I read and convert the ubyte[] back to the struct:

uint len = ss.read(buffer);
auto mem = new mem_stream(buffer[0 .. len]);
data d = mem.read!(data);
writefln("[id:%d] len=%d, data=%s (%d)", d.id, len, d.content,
d.content.sizeof);

Which outputs:    [id:100] len=12, data= (8)

The read function:
..
int pos = 0;
..
T read(T)()
{
     T output = *(cast(T*)(buf[pos .. pos + T.sizeof].ptr));
     pos += T.sizeof;
     return output;
}

The Integer got sent perfectly (and i does the same with additional ulongs
etc.) but the char[] did not, though, it is still the same size.

So why can't I send the char[]? is it because it is a array of pointers to the
address-space of the server?

Thank you in advance :)

(Btw. My files are also attatched)
Mar 06 2007
next sibling parent reply BCS <ao pathlink.com> writes:
Reply to SirErugor,

 Hi there,
 
 I've set up a server and a client application and I want to be able to
 send a struct with fx. an integer and a char[]. So first I convert it
 to a ubyte[] like this:
 
 ..
 void write(T)(T input)
 {
 buf ~= *(cast(ubyte[T.sizeof]*)&input)[0 .. T.sizeof];
 }
 Then I send the ubyte[] over through TCP via a SocketStream. On the
 client-side I read and convert the ubyte[] back to the struct:
 
 uint len = ss.read(buffer);
 auto mem = new mem_stream(buffer[0 .. len]);
 data d = mem.read!(data);
 writefln("[id:%d] len=%d, data=%s (%d)", d.id, len, d.content,
 d.content.sizeof);
 Which outputs:    [id:100] len=12, data= (8)
 
 The read function:
 ..
 int pos = 0;
 ..
 T read(T)()
 {
 T output = *(cast(T*)(buf[pos .. pos + T.sizeof].ptr));
 pos += T.sizeof;
 return output;
 }
 The Integer got sent perfectly (and i does the same with additional
 ulongs etc.) but the char[] did not, though, it is still the same
 size.
 
 So why can't I send the char[]? is it because it is a array of
 pointers to the address-space of the server?
 
 Thank you in advance :)
 
 (Btw. My files are also attatched)
 
char[] is by reference. under the hood it is a pointer/length pair. Somewhere I have a code generator that tries to make this work.
Mar 06 2007
parent reply BCS <ao pathlink.com> writes:
Reply to Benjamin,

 Reply to SirErugor,
 
 Hi there,
 
 I've set up a server and a client application and I want to be able
 to send a struct with fx. an integer and a char[]. So first I convert
 it to a ubyte[] like this:
 
 ..
 void write(T)(T input)
 {
 buf ~= *(cast(ubyte[T.sizeof]*)&input)[0 .. T.sizeof];
 }
 Then I send the ubyte[] over through TCP via a SocketStream. On the
 client-side I read and convert the ubyte[] back to the struct:
 uint len = ss.read(buffer);
 auto mem = new mem_stream(buffer[0 .. len]);
 data d = mem.read!(data);
 writefln("[id:%d] len=%d, data=%s (%d)", d.id, len, d.content,
 d.content.sizeof);
 Which outputs:    [id:100] len=12, data= (8)
 The read function:
 ..
 int pos = 0;
 ..
 T read(T)()
 {
 T output = *(cast(T*)(buf[pos .. pos + T.sizeof].ptr));
 pos += T.sizeof;
 return output;
 }
 The Integer got sent perfectly (and i does the same with additional
 ulongs etc.) but the char[] did not, though, it is still the same
 size.
 So why can't I send the char[]? is it because it is a array of
 pointers to the address-space of the server?
 
 Thank you in advance :)
 
 (Btw. My files are also attatched)
 
char[] is by reference. under the hood it is a pointer/length pair. Somewhere I have a code generator that tries to make this work.
ftp://ftp.novell.uidaho.edu/public_html/netidl_0_12_sdk.zip somewhere in there is a template that will suck up arrays (and arrays of arrays, ...) and let you send them over the wire. try running the program on a file like this interface foo { void bar(char[] i); void big(char[][] i); } I haven't looked at it for ages so I won't make any claims about how well it will work.
Mar 06 2007
parent reply SirErugor <ontherenth gmail.com> writes:
BCS Wrote:

 Reply to Benjamin,
 
 ftp://ftp.novell.uidaho.edu/public_html/netidl_0_12_sdk.zip
 
 somewhere in there is a template that will suck up arrays (and arrays of 
 arrays, ...) and let you send them over the wire.
 
 try running the program on a file like this
 
 interface foo
 {
   void bar(char[] i);
   void big(char[][] i);
 }
 
 I haven't looked at it for ages so I won't make any claims about how well 
 it will work.
Thanks BCS, But I cannot access the file? Not even as anonymous. Could you please either post the file here or send it to my email? :-) Cheers!
Mar 08 2007
parent BCS <ao pathlink.com> writes:
Reply to SirErugor,

 BCS Wrote:
 
 Reply to Benjamin,
 
 ftp://ftp.novell.uidaho.edu/public_html/netidl_0_12_sdk.zip
 
 somewhere in there is a template that will suck up arrays (and arrays
 of arrays, ...) and let you send them over the wire.
 
 try running the program on a file like this
 
 interface foo
 {
 void bar(char[] i);
 void big(char[][] i);
 }
 I haven't looked at it for ages so I won't make any claims about how
 well it will work.
 
Thanks BCS, But I cannot access the file? Not even as anonymous. Could you please either post the file here or send it to my email? :-) Cheers!
Damb stupid firefox. No, wait, That was my bad. <g> http://www.uidaho.edu/~shro8822/netidl_0_12_sdk.zip That should work.
Mar 08 2007
prev sibling parent reply Downs <default_357-line yahoo.de> writes:
SirErugor wrote:
 Hi there,
 
 I've set up a server and a client application and I want to be able to send a
struct with fx. an integer and a char[]. So first I convert it to a ubyte[]
like this:
 
This is rather easy to achieve with templates I needed to do something similar a bit back, so here's the code I used: template isArray(T) { const isArray=false; } template isArray(T: T[]) { const isArray=true; } /// serialize void ser(T)(T value, void delegate(char[]) dg) { static if (isArray!(T)) { /// First dump the length (as uint, so it's fixed across platforms), then the data /// \todo special case for char[] arrays ser!(uint)(value.length, dg); foreach (element; value) ser(element, dg); } else { static if (is(T==struct)) { /// Just serialize the elements in order foreach (element; value.tupleof) ser(element, dg); } else { dg((cast(char*)&value)[0..value.sizeof]); } } } void ser(T, dummy=void)(T value, inout char[] target) { ser!(T)(value, (char[] c) { target~=c; }); } char[] splinter(inout char[] c, size_t amount) { assert(c.length!<amount); auto res=c[0..amount]; c=c[amount..$]; return res; } T carve(T)(inout char[] t) { T result; static if (isArray!(T)) { result.length=carve!(uint)(t); foreach (inout elem; result) elem=carve!(typeof(result[0]))(t); } else { static if (is(T==struct)) { foreach (idx, bogus; result.tupleof) result.tupleof[idx]=carve!(typeof(bogus))(t); } else { result=*(cast(T*)(splinter(t, T.sizeof).ptr)); } } return result; } Use it like struct test { int e; char[] f; } char[] send; test t; ser(t, (char[] c) { send~=c; }); /* Now send "send" over the socket .. at the other end: */ char[] received; test t=carve!(test)(received); Greetings --downs
Mar 08 2007
parent reply SirErugor <ontherenth gmail.com> writes:
Downs Wrote:
 This is rather easy to achieve with templates
 I needed to do something similar a bit back, so here's the code I used:
 
 template isArray(T) { const isArray=false; }
 template isArray(T: T[]) { const isArray=true; }
 
 /// serialize
 void ser(T)(T value, void delegate(char[]) dg) {
    static if (isArray!(T)) {
      /// First dump the length (as uint, so it's fixed across platforms), then
the data
      /// \todo special case for char[] arrays
      ser!(uint)(value.length, dg);
      foreach (element; value) ser(element, dg);
    } else {
      static if (is(T==struct)) {
        /// Just serialize the elements in order
        foreach (element; value.tupleof) ser(element, dg);
      } else {
        dg((cast(char*)&value)[0..value.sizeof]);
      }
    }
 }
 
 void ser(T, dummy=void)(T value, inout char[] target) {
    ser!(T)(value, (char[] c) { target~=c; });
 }
 
 char[] splinter(inout char[] c, size_t amount) {
    assert(c.length!<amount);
    auto res=c[0..amount];
    c=c[amount..$];
    return res;
 }
 
 T carve(T)(inout char[] t) {
    T result;
    static if (isArray!(T)) {
      result.length=carve!(uint)(t);
      foreach (inout elem; result) elem=carve!(typeof(result[0]))(t);
    } else {
      static if (is(T==struct)) {
        foreach (idx, bogus; result.tupleof)
          result.tupleof[idx]=carve!(typeof(bogus))(t);
      } else {
        result=*(cast(T*)(splinter(t, T.sizeof).ptr));
      }
    }
    return result;
 }
 
 
 Use it like
 
 struct test {
    int e;
    char[] f;
 }
 char[] send; test t;
 ser(t, (char[] c) { send~=c; });
 /* Now send "send" over the socket .. at the other end: */
 char[] received; test t=carve!(test)(received);
 
 Greetings  --downs
Thank you very much, Downs! This works perfectly and I've gotten quite a better understanding on templates as well. Cheers! :)
Mar 09 2007
parent Downs <default_357-line yahoo.de> writes:
SirErugor wrote:
 Thank you very much, Downs!
 This works perfectly and I've gotten quite a better understanding on templates
as well.
 
 Cheers! :)
Glad to be of service :D
Mar 09 2007