locked
StreamSocket block on DataReader LoadAsync

    Question

  • Hello,

    I am running into an issue in my application that uses a StreamSocket object in c++/cx.  I am running into a case where the LoadAsync method of a DataReader that is tied to the SocketStream's InputStream is not returning.  Is there a way to get this to timeout after a while?

    Thanks

    auto socket = ref new SocketStream();
    socket->ConnectAsync();
    ...
    auto reader = ref new DataReader(socket->InputStream);
    reader->InputStreamOptions = InputStreamOptions::Partial;
    
    auto loadTask = create_task(reader->LoadAsync());
    auto readTask = loadTask.then([](unsigned int bytes) ->
    {
    
    ....
    }

    Thursday, January 17, 2013 10:37 PM

Answers

  • Hi,

    Did you call the _cancelTokenSource.cancel(); in a work thread?
    Or did you use try-catch block to get the cancel return from the task?

    Here is a parts of codes in StreqamSocket sample. How it can help you. The sample cancel the socket in a task

       // Read first 4 bytes (length of the subsequent string).
        task<unsigned int>(reader->LoadAsync(sizeof(UINT32))).then([this, reader, socket] (unsigned int size)
        {
            if (size < sizeof(UINT32))
            {
                // The underlying socket was closed before we were able to read the whole data.
                cancel_current_task();
            }
    
            unsigned int stringLength = reader->ReadUInt32();
            return task<unsigned int>(reader->LoadAsync(stringLength)).then([this, reader, stringLength] (unsigned int actualStringLength)
            {
                if (actualStringLength != stringLength)
                {
                    // The underlying socket was closed before we were able to read the whole data.
                    cancel_current_task();
                }
                
                // Display the string on the screen. This thread is invoked on non-UI thread, so we need to marshal the call back to the UI thread.
                NotifyUserFromAsyncThread("Received data: \"" + reader->ReadString(actualStringLength) + "\"", NotifyType::StatusMessage);
            });
        }).then([this, reader, socket] (task<void> previousTask)
        {
            try
            {
                // Try getting all exceptions from the continuation chain above this point.
                previousTask.get();
    
                // Everything went ok, so try to receive another string. The receive will continue until the stream is broken (i.e. peer closed closed the socket).
                ReceiveStringLoop(reader, socket);
            }
            catch (Exception^ exception)
            {
                NotifyUserFromAsyncThread("Read stream failed with error: " + exception->Message, NotifyType::ErrorMessage);
    
                // Explicitly close the socket.
                delete socket;
            }
            catch (task_canceled&)
            {
                // Do not print anything here - this will usually happen because user closed the client socket.
    
                // Explicitly close the socket.
                delete socket;
            }
        });
    http://code.msdn.microsoft.com/windowsapps/StreamSocket-Sample-8c573931

    Best regards,
    Jesse


    Jesse Jiang
    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.

    • Marked as answer by Jesse Jiang Wednesday, January 23, 2013 3:00 AM
    Monday, January 21, 2013 6:09 AM

All replies

  • In the LoadAsync() method, you have to provide the number of bytes you would like to load. When you call LoadAsync() it loads data from network to your local buffer, then you have to read the loaded bytes from your local storage.

    Reminder

    TCP does not operate on packets of data, rather operates on streams of data. Here message boundaries are not preserved by the underlying protocol. It means, a single Send will always not result in a single Receive. So in TCP, your apps should maintain message framing (e.g. length prefixing and delimiters). Sender and Receiver should agree in a common technique.


    Friday, January 18, 2013 3:42 AM
  • I should have elaborated further.  There is a point when I want to shutdown my application and I want to close down all pending operations.  When I create the loadTask I am also passing a cancellation_token to it and when I want to cancel all the operations, I call the cancel method on the cancellation_token_source.  However the load operation is not canceling.

     auto loadTask = create_task(_inputReader->LoadAsync(bufferLength), _cancelTokenSource.get_token());
    task<IBuffer^> readTask = loadTask.then([this, bufferLength] (unsigned int bytesRead) -> IBuffer^
    {
    ...
    }
    
    
    // in other thread:
    _cancelTokenSource.cancel();

    Friday, January 18, 2013 3:54 PM
  • Hi,

    Did you call the _cancelTokenSource.cancel(); in a work thread?
    Or did you use try-catch block to get the cancel return from the task?

    Here is a parts of codes in StreqamSocket sample. How it can help you. The sample cancel the socket in a task

       // Read first 4 bytes (length of the subsequent string).
        task<unsigned int>(reader->LoadAsync(sizeof(UINT32))).then([this, reader, socket] (unsigned int size)
        {
            if (size < sizeof(UINT32))
            {
                // The underlying socket was closed before we were able to read the whole data.
                cancel_current_task();
            }
    
            unsigned int stringLength = reader->ReadUInt32();
            return task<unsigned int>(reader->LoadAsync(stringLength)).then([this, reader, stringLength] (unsigned int actualStringLength)
            {
                if (actualStringLength != stringLength)
                {
                    // The underlying socket was closed before we were able to read the whole data.
                    cancel_current_task();
                }
                
                // Display the string on the screen. This thread is invoked on non-UI thread, so we need to marshal the call back to the UI thread.
                NotifyUserFromAsyncThread("Received data: \"" + reader->ReadString(actualStringLength) + "\"", NotifyType::StatusMessage);
            });
        }).then([this, reader, socket] (task<void> previousTask)
        {
            try
            {
                // Try getting all exceptions from the continuation chain above this point.
                previousTask.get();
    
                // Everything went ok, so try to receive another string. The receive will continue until the stream is broken (i.e. peer closed closed the socket).
                ReceiveStringLoop(reader, socket);
            }
            catch (Exception^ exception)
            {
                NotifyUserFromAsyncThread("Read stream failed with error: " + exception->Message, NotifyType::ErrorMessage);
    
                // Explicitly close the socket.
                delete socket;
            }
            catch (task_canceled&)
            {
                // Do not print anything here - this will usually happen because user closed the client socket.
    
                // Explicitly close the socket.
                delete socket;
            }
        });
    http://code.msdn.microsoft.com/windowsapps/StreamSocket-Sample-8c573931

    Best regards,
    Jesse


    Jesse Jiang
    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.

    • Marked as answer by Jesse Jiang Wednesday, January 23, 2013 3:00 AM
    Monday, January 21, 2013 6:09 AM
  • Hi,

    I marked my reply as answer, if your issue has not been solved please unmark it and update more information about this issue.

    Best regards,
    Jesse


    Jesse Jiang
    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 23, 2013 3:01 AM