Thread overview
Sending a struct over TCP
Mar 06, 2007
SirErugor
Mar 06, 2007
BCS
Mar 06, 2007
BCS
Mar 08, 2007
SirErugor
Mar 08, 2007
BCS
Mar 08, 2007
Downs
Mar 09, 2007
SirErugor
Mar 09, 2007
Downs
March 06, 2007
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)


March 06, 2007
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.


March 06, 2007
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.


March 08, 2007
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
March 08, 2007
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!
March 08, 2007
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.


March 09, 2007
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! :)
March 09, 2007
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