30
$\begingroup$

I noticed an undocumented socket package (SocketLink) in Mathematica (Using version 10, not sure when it was actually added) and wrote a barebones HTTP responder using it:

<<SocketLink`
host = "localhost";
port = 9999;
eol = "\r\n";
helloHTML = 
  "<html><head><title>Hello world!</title></head><body>Hello world!</body></html>";
response = "HTTP/1.1 200 OK"<>eol<>
    "Content-length: "<>ToString[StringLength[helloHTML<>eol]]<>eol<>eol<>
    helloHTML<>eol;
handler[streams_] := Module[{
        inStream = streams[[1]],
        outStream = streams[[2]],
        req = {},
        reqString
    },
    While[!MatchQ[req, {___, 13, 10, 13, 10}],
        AppendTo[req, BinaryRead[inStream]];
    ];
    Close[inStream];
    reqString = FromCharacterCode[req];
    (* print request *)
    Print[reqString];
    BinaryWrite[outStream, ToCharacterCode[response]];
    Close[outStream];
];

s = CreateServerSocket[port]
ser = CreateAsynchronousServer[s, handler]

The issue is that I have no way of telling when there is no more content in the input stream. This is a problem because if I read once byte beyond this the kernel crashes. I get around it in the above code by reading each character individually and using pattern matching to detect when the request ends (at "\r\n\r\n"):

While[!MatchQ[req, {___, 13, 10, 13, 10}],
    AppendTo[req, BinaryRead[inStream]];
];

This is will work with properly formed requests but if the request is malformed the kernel crash is unavoidable as far as I can see. I realize implementing an HTTP server in Mathematica is a silly endeavour but I would like to know if there is a way of detecting the "end" of a socket stream for other potentially nontrivial uses of SocketLink.

$\endgroup$
8
$\begingroup$

I was playing around SocketLink too. (And tried implementing a "pure" Mathematica server too!). About the OP's question, on my Windows 8.1 64bit, Doing more BinaryRead[inStream] than necessary will not crash the kernel, it will just wait for input, which blocks the main link. My workaround for this is using TimeConstrained:

While[True,
      TimeConstrained[AppendTo[req, BinaryRead[inStream]], 0.01, Break[]];
     ]

This is surely not the best way to go, but unfortunately I don't know C++ enough to modify the source code of SocketLink's libraries.

$\endgroup$
7
$\begingroup$

Beginning with Mathematica 10 there is a new function ReadString to get the (current) available data from an open socket connection by setting EndOfBuffer as terminator.

But there has to be at least one finished read to the stream before ReadString[socket, EndOfBuffer] will return the next chunk.

Basic stream function StreamPosition, SetStreamPosition will also work.

Hint: try OpenRead, OpenWrite on SocketObject creates underlying stream objects.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.