Jump to page: 1 2
Thread overview
Sockets between D and C(++) app
Apr 02, 2014
Alexandre L.
Apr 02, 2014
bearophile
Apr 02, 2014
Alexandre L.
Apr 02, 2014
Alexandre L.
Re: Signature of main [was Sockets between D and C(++) app]
Apr 02, 2014
Russel Winder
Apr 02, 2014
bearophile
Apr 02, 2014
Dicebot
Apr 02, 2014
Andrej Mitrovic
Apr 02, 2014
FreeSlave
Apr 03, 2014
Alexandre L.
April 02, 2014
Hello,
I lately did a minimal udp socket server-client application with C++, and I've been trying to recreate it with D, after.

I'm able to get the client's request (C++ client) without too much trouble (after I figured I needed to get it in ubyte[]).

Then I've tried to send the client an answer through send() (then tried sendTo() ) but none of them work.

Here's my 'server' code:

int main(string[] args)
{
	auto s = new UdpSocket();

	auto addr = new InternetAddress("127.0.0.1", 6666);
	s.setOption(SocketOptionLevel.IP, SocketOption.REUSEADDR, true);
	s.bind(addr);

	while (true)
	{
		ubyte[2048] recv_buf;
		int count = s.receiveFrom(recv_buf);
		char[] test = cast(char[])recv_buf[0..count-1]; // -1 for C string comp.

		writefln("Received: %s\n", test);

		char[] rep = "regan\0".dup;
		
		s.send(cast(ubyte[])rep);
	}

	writeln("End!");

	return 0;
}

Then the client tries to get the string in a std::string, hence why I did input the \0 literal. I'm also fairly new to D, so any guidance is sure welcomed!

Alexandre
April 02, 2014
Alexandre L.:

Some comments on your code:

> Here's my 'server' code:
>
> int main(string[] args)
> {

If you don't need args, then I suggest to not put it as main argument. So probably this is better (note no int nor return, in D they are not needed):

void main() {
...
}


> 		int count = s.receiveFrom(recv_buf);

It's better to use immutable here, and infer the type (use const/immutable everywhere you don't really need to mutate a variable/argument/field):

		immutable count = s.receiveFrom(recv_buf);


> 		char[] test = cast(char[])recv_buf[0..count-1]; // -1 for C string comp.
>
> 		writefln("Received: %s\n", test);
>
> 		char[] rep = "regan\0".dup;
> 		
> 		s.send(cast(ubyte[])rep);

casts are dangerous, because they silently assume you know what you are doing. As first try I suggest you to remove every cast() from your D program, and replace them with to!() or other functions like toStringz. Sometimes this is not the most efficient thing to do, but it's safer, so it's better when you start to learn D.

Bye,
bearophile
April 02, 2014
On Wednesday, 2 April 2014 at 00:34:08 UTC, bearophile wrote:
>> 		char[] rep = "regan\0".dup;
>> 		
>> 		s.send(cast(ubyte[])rep);
>
> casts are dangerous, because they silently assume you know what you are doing. As first try I suggest you to remove every cast() from your D program, and replace them with to!() or other functions like toStringz. Sometimes this is not the most efficient thing to do, but it's safer, so it's better when you start to learn D.
>
> Bye,
> bearophile

Thanks for your reply. As for cast, I seems not to have any option, because to! doesn't work as I would expect it. It would return me an array of numbers, instead of a string; So I kept the cast here, since I certainly know what it's doing -for now-.

I generally use immutables, you caught me, here :-). As of main and return, I was not aware we could just ignore them if we didn't need them. I love explicit programming.

However, I'm still stuck with toStringz(). Since it returns an immutable(char[]), I can't find how to pass it to Socket.send(), and I do not seem to be able to cast away the immutable :-s

Alexandre
April 02, 2014
My bad; It returns immutable(char)*.

Still won't work with send(); Am I right to supposed the receiving client must handle a ubyte[] as well (C++) ?
April 02, 2014
On Wed, 2014-04-02 at 00:34 +0000, bearophile wrote:
> Alexandre L.:

> > int main(string[] args)
> > {
> 
> If you don't need args, then I suggest to not put it as main argument. So probably this is better (note no int nor return, in D they are not needed):
> 
> void main() {
> ...
> }

I am not convinced by this argument. The return value (aka exit code) is always present, if you ignore this by having a void main, it will return 0, i.e. main is not a void function even if you claim it is. As for ignoring the parameters, this is making use of the fact that main is the only function where you do not have to present the correct signature. Perhaps this exception should be removed.

The real signature of main in C/C++ is, I believe:

        int main(int, char**, char**)

what is the real signature in D?

-- 
Russel. ============================================================================= Dr Russel Winder      t: +44 20 7585 2200   voip: sip:russel.winder@ekiga.net 41 Buckmaster Road    m: +44 7770 465 077   xmpp: russel@winder.org.uk London SW11 1EN, UK   w: www.russel.org.uk  skype: russel_winder

April 02, 2014
Russel Winder:

> what is the real signature in D?

The _real_ signature of main() is flexible, you can use:

void main()
int main(in string[] args) pure nothrow

D allows you to omit the args if you don't need them, returns 0 if you don't it, and it can be pure/nothrow/@safe as desired.


> Perhaps this exception should be removed.

This special cases cause zero bugs and zero problems, so there is no chance to change this, even if we want (and I don't want).

Bye,
bearophile
April 02, 2014
On Wednesday, 2 April 2014 at 08:55:23 UTC, Russel Winder wrote:
> On Wed, 2014-04-02 at 00:34 +0000, bearophile wrote:
>> Alexandre L.:
>
>> > int main(string[] args)
>> > {
>> 
>> If you don't need args, then I suggest to not put it as main argument. So probably this is better (note no int nor return, in D they are not needed):
>> 
>> void main() {
>> ...
>> }
>
> I am not convinced by this argument. The return value (aka exit code) is
> always present, if you ignore this by having a void main, it will return
> 0, i.e. main is not a void function even if you claim it is. As for
> ignoring the parameters, this is making use of the fact that main is the
> only function where you do not have to present the correct signature.
> Perhaps this exception should be removed.
>
> The real signature of main in C/C++ is, I believe:
>
>         int main(int, char**, char**)
>
> what is the real signature in D?

D main != C main, latter is implemented in D runtime to call the former. 0 will be also returned by latter, not the former. Also exception will result in >0 status code even if return type is void. It effectively just says that you won't manage status code manually and allows runtime to take care of it.
April 02, 2014
On 4/2/14, Dicebot <public@dicebot.lv> wrote:
> D main != C main, latter is implemented in D runtime to call the former. 0 will be also returned by latter, not the former.

Actually, the compiler injects a return statement in D's main.

It generates the actual C main function (unless WinMain/DllMain is provided), which calls another special D runtime init function, which itself calls the D main function (which itself has the injected return statement unless it's already an int return).

It's quite complicated, but it's all open-source so you can inspect it.
April 02, 2014
On Wednesday, 2 April 2014 at 08:55:23 UTC, Russel Winder wrote:
> The real signature of main in C/C++ is, I believe:
>
>         int main(int, char**, char**)

I believe in C it is:

int main(void)
int main(int,char**)

or implementation defined (e.g. the third env pointer in the main signature from unix)

But the actual entry point is system dependent and can be specified as a link option? On linux "_start" or something like that.
April 02, 2014
It's only server. Maybe problem is on client side.

Try this if you are on Linux:

//Linux C client
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stddef.h>
#include <string.h>
#include <stdio.h>

int main()
{
    int sock, res;
    struct sockaddr_in addr;
    const char* hello;
    size_t len;

    sock = socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0)
    {
        printf("Can't create socket\n");
        return -1;
    }

    addr.sin_family = AF_INET;
    addr.sin_port = htons(5432);
    addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    hello = "Hello from C";
    len = strlen(hello);
    while (1)
    {
        res = sendto(sock, hello, len, 0, (struct sockaddr*)&addr, sizeof(addr));
        if (res <= 0)
        {
            printf("Can't send\n");
            return -1;
        }
    }
    close(sock);
    return 0;
}


//D server
import std.socket;
import std.stdio;

int main(string[] args)
{
    auto s = new UdpSocket(AddressFamily.INET);

    auto addr = new InternetAddress("127.0.0.1", 5432);
    s.setOption(SocketOptionLevel.IP, SocketOption.REUSEADDR, true);
    s.bind(addr);

    while (true)
    {
        ubyte[2048] recv_buf;
        int count = s.receiveFrom(recv_buf[]);
        char[] test = cast(char[])recv_buf;

        writefln("Received: %s\n", test);
    }
    return 0;
}


Note that you don't need to remove zero-symbol if you don't pass it from client.
« First   ‹ Prev
1 2