Thread overview
Receiving data into a type using sockets
Jun 05, 2011
Jonathan Sternberg
Jun 05, 2011
David Nadlinger
Jun 05, 2011
Jonathan Sternberg
Jun 05, 2011
David Nadlinger
Jun 05, 2011
Andrew Wiley
June 05, 2011
I'm trying to learn how to do some networking code in D. In C, if I wanted to read 4 bytes into an integer, I could just do (ignoring any error detection):

int foo;
recv(sockfd, &foo, sizeof(int), 0);

How do I do this with D? The receive function takes in a void [] parameter and doesn't take in a number of bytes to read. Is there anyway to accomplish this in D?
June 05, 2011
On 6/5/11 8:51 PM, Jonathan Sternberg wrote:
> I'm trying to learn how to do some networking code in D. In C, if I wanted to
> read 4 bytes into an integer, I could just do (ignoring any error detection):
>
> int foo;
> recv(sockfd,&foo, sizeof(int), 0);
>
> How do I do this with D? The receive function takes in a void [] parameter and
> doesn't take in a number of bytes to read. Is there anyway to accomplish this
> in D?

auto socket = new Socket(…);
…
int foo;
socket.receive((&foo)[0..1]);

---

void[] is like an array of bytes, with the difference to ubyte[] being that it can contain pointers which must be taken into account by the GC, and implicit convertibility. However, all the socket functions should operate on ubyte[] instead of void[] by current guidelines – the socket module is really old, this will definitely be changed when it will be overhauled/replaced.

David
June 05, 2011
Cool. It compiles, but it doesn't seem to be doing exactly what I want. Say I send 2 integers from the server to the client. When I do this on the client, it seems to do the wrong thing.

int first, second;
auto sock = new TcpSocket();
sock.connect(new InternetAddress("localhost", 10000));

writeln( sock.receive((&first)[0..int.sizeof]) );
writeln( sock.receive((&second)[0..int.sizeof] );

This seems to print 8 and then block on the second call to receive. I thought that D was supposed to recognize that the array was only 4 bytes long and read only that much. (note: on a 32-bit machine, so int comes out to 4 bytes)

When I do:

writeln( (&first)[0..int.sizeof].length );

It prints 4 as it's supposed to.
June 05, 2011
On 6/5/11 9:49 PM, Jonathan Sternberg wrote:
> Cool. It compiles, but it doesn't seem to be doing exactly what I want. Say I send
> 2 integers from the server to the client. When I do this on the client, it seems
> to do the wrong thing.
>
> int first, second;
> auto sock = new TcpSocket();
> sock.connect(new InternetAddress("localhost", 10000));
>
> writeln( sock.receive((&first)[0..int.sizeof]) );
> writeln( sock.receive((&second)[0..int.sizeof] );
>
> This seems to print 8 and then block on the second call to receive. I thought that
> D was supposed to recognize that the array was only 4 bytes long and read only
> that much. (note: on a 32-bit machine, so int comes out to 4 bytes)
>
> When I do:
>
> writeln( (&first)[0..int.sizeof].length );
>
> It prints 4 as it's supposed to.

&first is of type int*, so (&first)[0..int.sizeof] returns a slice pointing to int.sizeof (i.e. 4) ints, not a single one as you intend to. Just use »(&first)[0..1]« as per my original reply, and you should be fine.

David
June 05, 2011
On Sun, Jun 5, 2011 at 12:55 PM, David Nadlinger <see@klickverbot.at> wrote:

> On 6/5/11 9:49 PM, Jonathan Sternberg wrote:
>
>> Cool. It compiles, but it doesn't seem to be doing exactly what I want.
>> Say I send
>> 2 integers from the server to the client. When I do this on the client, it
>> seems
>> to do the wrong thing.
>>
>> int first, second;
>> auto sock = new TcpSocket();
>> sock.connect(new InternetAddress("localhost", 10000));
>>
>> writeln( sock.receive((&first)[0..int.sizeof]) );
>> writeln( sock.receive((&second)[0..int.sizeof] );
>>
>> This seems to print 8 and then block on the second call to receive. I
>> thought that
>> D was supposed to recognize that the array was only 4 bytes long and read
>> only
>> that much. (note: on a 32-bit machine, so int comes out to 4 bytes)
>>
>> When I do:
>>
>> writeln( (&first)[0..int.sizeof].length );
>>
>> It prints 4 as it's supposed to.
>>
>
> &first is of type int*, so (&first)[0..int.sizeof] returns a slice pointing
> to int.sizeof (i.e. 4) ints, not a single one as you intend to. Just use
> »(&first)[0..1]« as per my original reply, and you should be fine.
>

Also, note that receive is basically a direct call to C's receive, which
means that it has the same behavior with regards to buffer filling. Calling
sock.receive((&first)[0..1]) returns the number of bytes read, which may be
less than 4. I've handled this in the past by writing a template function
that takes a primitive type and loops until it has read all the bytes it
needs.
Oh, and D's int is always 32 bits, on 32 bit or 64 bit platforms. size_t is
an alias that switches from uint on 32 bit to ulong on 64 bit, and there's
another alias somewhere for signed types (ssize_t, I believe). The primitive
types always have the same sizes until you get into things like cent.