adamdruppe / arsd

This is a collection of modules that I've released over the years. Most of them stand alone, or have just one or two dependencies in here, so you don't have to download this whole repo.
http://arsd-official.dpldocs.info/arsd.html
531 stars 128 forks source link

WebSocket Client Server: Client sends empty records #250

Closed andre2007 closed 4 years ago

andre2007 commented 4 years ago

I have this WebSocket Echo example:

server.d

/+ dub.sdl:
    name "server"
    dependency "arsd-official:cgi" version="6.0.2"
+/

import std;
import arsd.cgi;

void main() 
{
    writeln("Listening on port 5000");
    processPoolSize = 1;
    cgiMainImpl!((cgi) { websocketEcho(cgi); }, Cgi, defaultMaxContentLength)(["--port", "5000"]);
}

void websocketEcho(Cgi cgi) {
    assert(cgi.websocketRequested(), "i want a web socket!");
    auto websocket = cgi.acceptWebsocket();

    try
    {
        while(websocket.recvAvailable(300.seconds)) 
        {
            auto msg = websocket.recv();
            if (msg.opcode == WebSocketOpcode.close) break;
            websocket.send(msg.data);

        }
        websocket.close();
    }
    catch(ConnectionClosedException e)
    {
        writeln("[Warning] Client disconnect detected");
    }
}

client.d

/+ dub.sdl:
    name "client"
    dependency "arsd-official:http" version="6.0.2"
    subConfiguration "arsd-official:http" "without_openssl"
+/

import std;
import arsd.http2;

void main() 
{
    ubyte[] data = [0, 1, 2];
    Uri uri = "ws://localhost:5000";
    auto ws = new WebSocket(uri);
    ws.connect();

    foreach(i; 0..50)
    {
        ubyte[] recvBuffer = ws.blockingSend(data);
        assert(recvBuffer == data, to!string(recvBuffer));
    }
}

ubyte[] blockingSend(WebSocket ws, ubyte[] inputBuffer)
{
    ws.send(inputBuffer);
    ubyte[] recvBuffer;       
    ws.onbinarymessage = (in ubyte[] message) {
        recvBuffer = message.dup;
        WebSocket.exitEventLoop();
    };
    WebSocket.eventLoop();
    return recvBuffer;
}

On the second iteration, client sends empty data and therefore the assertion will throw an error.

adamdruppe commented 4 years ago

It works fine if you use it in the loop:

import std;
import arsd.http2;

void main()
{
    ubyte[] data = [0, 1, 2];
    Uri uri = "ws://localhost:5000";
    auto ws = new WebSocket(uri);
    ws.connect();

    int i = 50;

    ws.onbinarymessage = (in ubyte[] message) {
        i--;
        assert(message == data);
        if(i)
                ws.send(data);
        else
                ws.close();
    };

    ws.send(data);

    WebSocket.eventLoop();
}

But I see the problem now, exitEventLoop assumes it will only be used once - it sets the exit flag and then it stays set. You aren't supposed to use it this way.

so there's the fix now: https://github.com/adamdruppe/arsd/commit/c5cec0c8056bdd9ffdb38acb2df0acfd068eba61

andre2007 commented 4 years ago

Thanks Adam, it works now like a charm.