`Socket.receive` providing arbitrary packet sizes and hanging without sending EOF

Unazed Spectaculum unazed at spec.org
Sun Dec 17 01:21:53 UTC 2017


On Thursday, 14 December 2017 at 20:27:36 UTC, Ali Çehreli wrote:
> On 12/14/2017 11:55 AM, Unazed Spectaculum wrote:
>
>> This is the only function which has a call to `receiveAll`
>
>
> I marked my changes with [Ali]:
>
> import std.stdio;
> import std.socket;
> import std.conv;
> import std.json;
>
> ubyte[] receiveBytes(T)(T socket, size_t receiveCount)
> {
>     ubyte[] buffer = new ubyte[receiveCount];
>     size_t count = socket.receive(buffer);
>     // [Ali] Return null when there is no data
>     if (count == Socket.ERROR || count == 0) {
>         return null;
>     }
>     return buffer[0 .. count];
> }
>
> string receiveAll(T)(T socket, size_t segmentSize = 1024)
> {
>     ubyte[][] data;
>     size_t count = 0;
>
>     do
>     {
>         debug(1) writefln("Chunk %s", count);
>         auto part = receiveBytes(socket, segmentSize);
>         // [Ali] Done when there is no data
>         if (!part) {
>             break;
>         }
>         data ~= part;
>         writeln(data[count]);
>         if (!data)
>             break;
>
>     } while(data[count++]);
>
>     char[] stringData;
>
>     foreach (elem; data)
>         stringData ~= elem;
>
>     debug(1) writeln(`Exiting "receiveAll"`);
>
>     return to!string(stringData);
> }
>
> void main()
> {
>     auto socket = new TcpSocket();
>     // [Ali]    setupSocket(socket, "0.0.0.0", 6969);
>     // The following had worked in a test program:
>     socket.setOption(SocketOptionLevel.SOCKET, 
> SocketOption.REUSEADDR, true);
>     socket.bind(new InternetAddress(6969));
>     socket.listen(1);
>
>     writefln("Listening: %s", socket.localAddress);
>
>     while(true)
>     {
>         Socket client = socket.accept();
>         debug(1) writefln("Client: %s", client.remoteAddress);
>
>         auto data = receiveAll(client);
>         writeln(data);
>         JSONValue json;
>
>         try {
>             json = parseJSON(data);
>         } catch (JSONException e) {
>             debug(1) writefln("Failed parsing data as JSON, 
> aborting.\n|| %s", e);
>             client.close();
>             continue;
>         } catch (Exception e) {
>             debug(1) writefln("Client caused exception:\n||%s", 
> e);
>             client.close();
>             continue;
>         }
>
>         /+ [Ali] Not important for this test
>         if (!verifyValues(json))
>         {
>             debug(1) writefln("Client missed out important key 
> fields: %s", client.remoteAddress);
>             client.close();
>             continue;
>         }
>         +/
>
>         debug(1) writeln("Client transacted successful JSON 
> packet.");
>
>         writefln("%s:\n\tFilename: %s\n\tMethod: %s\n\tData 
> length: %d",
>                 client.remoteAddress,
>                 json["filename"],
>                 json["method"],
>                 data.length
>             );
>
>         // [Ali] Not important for this test
>         /+
>         if (json["method"].str == "store")
>             storeData(json["filename"].str, json["data"].str);
>         else if (json["method"].str == "retrieve")
>             retrieveData(client, json["filename"].str);
>         +/
>         client.close();
>     }
> }
>
> 1) Start the program
>
> 2) $ telnet 0.0.0.0 6969
> Trying 0.0.0.0...
> Connected to 0.0.0.0.
> Escape character is '^]'.
>
> 3) Paste expected json to terminal:
>
> {"filename":"/tmp/foo","method":"bar"}
>
> 4) Press the escape character
>
> ^]
>
> 5) Press Ctrl-D (Ctrl-Z on Windows) to terminate the connection
>
> telnet> Connection closed.
>
> Here is the output from the program:
>
> Listening: 0.0.0.0:6969
> [123, 34, 102, 105, 108, 101, 110, 97, 109, 101, 34, 58, 34, 
> 47, 116, 109, 112, 47, 102, 111, 111, 34, 44, 34, 109, 101, 
> 116, 104, 111, 100, 34, 58, 34, 98, 97, 114, 34, 125, 13, 10]
> {"filename":"/tmp/foo","method":"bar"}
>
> 127.0.0.1:47704:
> 	Filename: "\/tmp\/foo"
> 	Method: "bar"
> 	Data length: 40
>
> I think it works! :)
>
> Ali

I've tried to integrate your code with mine; to no avail, I've 
directly tested your code; and yet again to no avail, so this 
should conclude the thread as it pinpoints an error with my 
actual OS.

Just in case, as a last resort in case I'm actually that dumb, 
here's me reproducing your steps:

1) Starting program
unazed at unazed  /home/d/storage-server  dmd -debug -run app.d
Listening: 0.0.0.0:6969

2) telnet to the server
  unazed at unazed  ~  telnet 0.0.0.0 6969
Trying 0.0.0.0...
Connected to 0.0.0.0.
Escape character is '^]'.

3) paste '{"filename":"/tmp/foo","method":"bar"}'
  unazed at unazed  /home/d/storage-server  dmd -debug -run app.d
Listening: 0.0.0.0:6969
Client: 127.0.0.1:55014
Chunk 0
[123, 34, 102, 105, 108, 101, 110, 97, 109, 101, 34, 58, 34, 47, 
116, 109, 112, 47, 102, 111, 111, 34, 44, 34, 109, 101, 116, 104, 
111, 100, 34, 58, 34, 98, 97, 114, 34, 125, 13, 10]
Chunk 1
[pause]

4-5) press ESC + CTRL+D (I'm on Linux)
Chunk 1
[27]
Chunk 2
[pause]

So, big thanks , and sorry for taking longer to respond; I just 
get anxious about solving things sometimes and now it's kind of 
annoying I have to do some more research to fix this issue.


More information about the Digitalmars-d-learn mailing list