locked
StreamSocket reader returning 0 bytes

    Question

  • I have used this example to write my connect and write/read from a socket.  That said, I have been able to successfully connect, and write to a device.  The device returns a packet, which I can see in wireshark, but the reader as per this example is not reading anything.  I have implemented it in the following function and am getting nothing in return.  Am I missing something simple here?

    function wWriteCmdResponse(writeCommand) {
    
        if (!m_SocketStream.connected) {
            console.log("Client: you must connect the client before using it.");
            return;
        }
    
        var writer = new Windows.Storage.Streams.DataWriter(m_SocketStream.clientSocket.outputStream);
        var reader; //= new Windows.Storage.Streams.DataReader(m_SocketStream.clientSocket.inputStream);
        var len = writer.measureString(writeCommand); // Gets the UTF-8 string length.
    
        writer.writeInt32(len);
        writer.writeString(writeCommand);
        console.log("Client sending: " + writeCommand + ".");
    
        writer.storeAsync().then(function () {
            console.log("Client sent: " + writeCommand + ".");
            return writer.flushAsync();
                }).then(function () {
                    stream = writer.detachStream();
                    writer.close();
                    reader = new Windows.Storage.Streams.DataReader(m_SocketStream.clientSocket.inputStream);
                    return reader.loadAsync(255).done(function () {
                        var receivedStrings = "";
                        // Keep reading until we consume the complete stream
                        while (reader.unconsumedBufferLength > 0) {
                            // Note that the call to readString requires a length of "code units" 
                            // to read. This is the reason each string is preceeded by its length 
                            // when "on the wire".
                            var codeUnitsToRead = reader.readInt32();
                            receivedStrings += reader.readString(codeUnitsToRead) + "<br/>";
                            var t1 = reader.unconsumedBufferLength;
                        }
    
            }, function () {
                console.log("Error.");
            });
    
        }, onError);
        
    
        
    };



    I have also tried the implementation that utilizes a listener to no avail.  Additionally, I have tried this approach and no luck...

    function wWriteCmdResponse(writeCommand) {
    
        if (!m_SocketStream.connected) {
            console.log("Client: you must connect the client before using it.");
            return;
        }
    
        var writer = new Windows.Storage.Streams.DataWriter(m_SocketStream.clientSocket.outputStream);
        var reader = new Windows.Storage.Streams.DataReader(m_SocketStream.clientSocket.inputStream);
        var len = writer.measureString(writeCommand); // Gets the UTF-8 string length.
        writer.writeInt32(len);
        writer.writeString(writeCommand);
        console.log("Client sending: " + writeCommand + ".");
        writer.storeAsync().done(function () {
            console.log("Client sent: " + writeCommand + ".");
        }, onError);
        
    
        reader.loadAsync(255);
        var t1 = reader.unconsumedBufferLength;
    };
    

    t1 also returns 0.

    Any thoughts or pointers in the right direction would be extremely helpful!

    Tuesday, January 15, 2013 10:45 PM

Answers

  • Hi MTAG11,

    You can certainly use Sockets if you know what you are sending and what type of response you are receiving. Since you have control over your server, you can certainly continue to use Sockets. If you were communicating with an internet server, then I would have recommended you to use the readymade classes since they implement the HTTP protocol for you and do all the parsing work for you. But, for custom server implementations, you are free to use the approach you prefer.

    It is just a balance of ease of use v/s implementing something from ground up when making the decision of using WinJS.xhr v/s StreamSocket.

    Thanks,

    Prashant.

    Wednesday, January 23, 2013 9:56 PM
    Moderator
  • Sure, you can certainly do that. You can connect to an IPv4 or IPv6 address/ port combination using the following syntax:

    IPv6:

            WinJS.xhr({ url: "http://[a:b:c:d:e:f:g:h]:port/relativePath/somePage" }).done(function complete(result) {
                // handle success
            }, function error(result) {
                // handle error
            }, function progress(result) {
                // handle progress
            });

    IPv4:

            WinJS.xhr({ url: "http://a.b.c.d:port/relativePath/somePage" }).done(function complete(result) {
                // handle success
            }, function error(result) {
                // handle error
            }, function progress(result) {
                // handle progress
            });

    as well as this approach:

            var objHttpClient = new XMLHttpRequest();
            objHttpClient.onload = OnURLLoad;
            objHttpClient.onerror = OnUrlError;

            //objHttpClient.open("GET", "http://a.b.c.d:port/relativePath/somePage", true);
            objHttpClient.open("GET", "http://[a:b:c:d:e:f:g:h]:port/relativePath/somePage", true);
            objHttpClient.send();

    Just make sure that you have the "Private Networks" capability checked in the package manifest file if the server you are testing against is on your private network. 

    Thursday, January 24, 2013 8:22 PM
    Moderator

All replies

  • Hi,

    Could you create a demo of that? And sharing on skydrive.


    Roy
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, January 16, 2013 9:13 AM
  • I have created a demo of this and am successfully recreating my problem. 


    The function labeled wWriteCmdResponse(writeCommand) will successfully send a packet to the local network address on the port I specified in the HTML (see project).  Once the device I'm connected to gets that packet it automatically responds with a data packet containing ASCII characters.  I need to return the response within the same function.

    It is on my public skydrive.  Do I need to do anything else?
    Wednesday, January 16, 2013 2:27 PM
  • I have a semi working wWriteCmdResponse(writeCommand).  I can get the data out of the packet.  I specified inputStreamOptions as partial and viola I am able to read the buffer.  The only problem now, and I don't see how to get around it, is that my function returns a blank value before reader.loadAsync has finished reading the buffer.  How can I get this to return within the same function, in turn.

    Here is the updated function.

    //WRITE COMMAND TO DEVICE, EXPECT RESPONSE BACK
    function wWriteCmdResponse(writeCommand) {
        var receivedStrings = "";
        try {
            if (!m_SocketStream.connected) {
                console.log("Client: you must connect the client before using it.");
                return;
            }
    
            var writer = new Windows.Storage.Streams.DataWriter(m_SocketStream.clientSocket.outputStream);
            var reader = new Windows.Storage.Streams.DataReader(m_SocketStream.clientSocket.inputStream);
            reader.inputStreamOptions = Windows.Storage.Streams.InputStreamOptions.partial;
            var stream;
    
            
            var len = writer.measureString(writeCommand); // Gets the UTF-8 string length.
            writer.writeInt32(len);
            writer.writeString(writeCommand);
    
            console.log("Client sending: " + writeCommand + ".");
    
            writer.storeAsync().done(function () {
                console.log("Client sent: " + writeCommand + ".");
            }, onError);
    
            reader.loadAsync(255).then(function () {
                while (reader.unconsumedBufferLength > 0) {
                    var codeUnitsToRead = reader.readByte();
                    receivedStrings += String.fromCharCode(codeUnitsToRead);
                }
                console.log(receivedStrings);
                
            });
        } catch (exception) {
            m_SocketStream.close();
            console.log("Closing socket connection." + exception.message)
        }
        return receivedStrings; //<----------- RETURNS BEFORE LOADASYNC CAN FILL THIS VARIABLE
    };


    • Edited by MTAG11 Wednesday, January 16, 2013 4:33 PM
    Wednesday, January 16, 2013 4:32 PM
  • Hi,

    Please post your skydrive address. Otherwise I can't get that.


    Roy
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, January 17, 2013 3:28 AM
  • Is that just my email address I signed into Win8 with?
    Thursday, January 17, 2013 1:42 PM
  • Hi,

    Yes, you can see the address when you log in skydrive.


    Roy
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, January 17, 2013 2:38 PM
  • Excellent.

    jt.bruch@powerdb.com
    Thursday, January 17, 2013 3:25 PM
  • Any update?
    Monday, January 21, 2013 4:20 PM
  • MMTAG11,

    In your read sample, you are running an asynchronous function to load data from the stream asynchronously. The receivedStrings variable will be populated only after the loadasync function completes. Returning from the wWriteCmdResponse function does not guarantee that the data is always ready before the function exits. You should consume your receivedStrings upon the completion of the loadasync function rather than the return value of wWriteCmdResponse. See this link that talks about asynchronous programming in JavaScript and how to handle promises: http://msdn.microsoft.com/en-us/library/windows/apps/hh700330.aspx.

    Also, you are only consuming 255 bytes of the response, what about response larger than 255 bytes? You should probably move your reading logic into a separate function and then create a recursive loop of reading data by calling loadasync multiple times until there is nothing more to read.

    Out of curiosity, why are you trying to create your own HTTP protocol implementation? WinJS does expose the xhr object that will give you HTTP protocol functionality. If you use direct sockets, you will need to implement the whole HTTP protocol yourself, which is a big task.

    Thanks,

    Prashant.

    Tuesday, January 22, 2013 6:27 PM
    Moderator
  • Prashant,

       Thank you for your response.  The reason I had 255 was just a number I picked, was planning on changing it later.  The reason I was trying to get it to return all in one function was that it would behave similarly to my other apps when I call it from the main UI thread.  Simply put, I'm looking for consistency.

      My UI in my app will call writeCmdResp(cmd), I then have an interface which determines what app its on, then it chooses the WinJS method.  Which then calls return wWriteCmdResp(Cmd) and expects to response back to the UI, hence my approach in the sample app.  

       The reason for creating the HTTP protocol, is that I simply need to connect directly to a IP address on my local network on port 8000.  The device on the other side of the socket is an instrument that I need to communicate with via send/receive commands.  The data coming back from the instrument will ALWAYS be ASCII.  Is this example the incorrect method of solving this problem?  Is there another way recommended by MSFT?  


    Wednesday, January 23, 2013 2:49 PM
  • Hi MTAG11,

    You can certainly use Sockets if you know what you are sending and what type of response you are receiving. Since you have control over your server, you can certainly continue to use Sockets. If you were communicating with an internet server, then I would have recommended you to use the readymade classes since they implement the HTTP protocol for you and do all the parsing work for you. But, for custom server implementations, you are free to use the approach you prefer.

    It is just a balance of ease of use v/s implementing something from ground up when making the decision of using WinJS.xhr v/s StreamSocket.

    Thanks,

    Prashant.

    Wednesday, January 23, 2013 9:56 PM
    Moderator
  • Can I connect to an IP address on a specific port with WinJS.xhr?
    Thursday, January 24, 2013 3:52 PM
  • Sure, you can certainly do that. You can connect to an IPv4 or IPv6 address/ port combination using the following syntax:

    IPv6:

            WinJS.xhr({ url: "http://[a:b:c:d:e:f:g:h]:port/relativePath/somePage" }).done(function complete(result) {
                // handle success
            }, function error(result) {
                // handle error
            }, function progress(result) {
                // handle progress
            });

    IPv4:

            WinJS.xhr({ url: "http://a.b.c.d:port/relativePath/somePage" }).done(function complete(result) {
                // handle success
            }, function error(result) {
                // handle error
            }, function progress(result) {
                // handle progress
            });

    as well as this approach:

            var objHttpClient = new XMLHttpRequest();
            objHttpClient.onload = OnURLLoad;
            objHttpClient.onerror = OnUrlError;

            //objHttpClient.open("GET", "http://a.b.c.d:port/relativePath/somePage", true);
            objHttpClient.open("GET", "http://[a:b:c:d:e:f:g:h]:port/relativePath/somePage", true);
            objHttpClient.send();

    Just make sure that you have the "Private Networks" capability checked in the package manifest file if the server you are testing against is on your private network. 

    Thursday, January 24, 2013 8:22 PM
    Moderator