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

Ali Çehreli acehreli at yahoo.com
Thu Dec 14 20:27:36 UTC 2017


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


More information about the Digitalmars-d-learn mailing list