locked
Handling multiple async responses with StreamSocketListener in C++

    Question

  • I'm trying to get this basic StreamSocketListener working between a traditional C# WPF app and a Windows 8 / Immersive C++ app.I am creating the StreamSocketListener in C++. The following code works fine if all I want to do is receive one message from a client. However, I'm having a bit of a conceptual challenge wrapping my head around how to adapt this single transaction, forced ASYNC solution into something that mimics the traditional while(true) { // blocking request, process client data } loop. Obviously, I can't just wrap up the ASYNC functions in a while loop, but somehow I need to have the nested handler respawn itself to read the NEXT bytes from the client.

    Anyone have any ideas for moving from a single transaction solution to a multiple reader->LoadAsync() solution in C++11? I'm really excited about C++ and don't mind the hard work moving from C#, but the lack of examples out there on StreamSockets in C++ has been a major challenge.
     
     
    SINGLE TRANSACTION SOLUTION


    MainPage^ page = this;

    txtOut->Text = "LISTENING FOR CLIENT... ";
    Windows::Networking::Sockets::StreamSocketListener^ socketListener = ref newStreamSocketListener("192.168.1.76");
    socketListener->ServiceName = "8888";
    auto AcceptOperationSocketListener = socketListener->AcceptAsync();
    AcceptOperationSocketListener->Completed = ref newAsyncOperationCompletedHandler<Windows::Networking::Sockets::StreamSocket^>(
    [page](IAsyncOperation<StreamSocket^> ^op)
    {
    if (op->Status == AsyncStatus::Completed)
    {
    page->txtOut->Text += "CLIENT ACCEPTED...";

    Windows::Networking::Sockets::StreamSocket^ stream = op->GetResults();
    IInputStream^ inputStream = stream->InputStream;
    Windows::Storage::Streams::DataReader^ reader = ref new Windows::Storage::Streams::DataReader(inputStream);
     reader->InputStreamOptions = InputStreamOptions::Partial;

    //HOW DO WE REPEAT THIS BLOCK TO READ IN MULTIPLE VALUES FROM THE CLIENT?

     
     Windows::Storage::Streams::DataReaderLoadOperation^ opRead = reader->LoadAsync(4);
     opRead->Completed = ref new AsyncOperationCompletedHandler<unsigned int>(
     [page, reader](IAsyncOperation<unsigned int> ^op)
     {
      int val = reader->ReadInt32();

      // CONVERT VALUE TO STRING AND DISPLAY IT
      std::wstringstream wss;
             wss << val;
      page->txtOut->Text = "FROM CLIENT: " + ref new Platform::String(wss.str().c_str());

      // USE VALUE TO SET A UI ELEMENT  Canvas::SetLeft(page->testRectangle, (double)val);
     });
     opRead->Start();   
    }
    });
    AcceptOperationSocketListener->Start();

    Thursday, October 6, 2011 2:39 AM

Answers

  • Here is how I got it working. Some real samples for StreamSocket in C++ from MSFT would be greatly appreciated though.

    MainPage.xaml.h:
    [...]
    private:
     void UserControl_Loaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
     void handleLoad( Windows::Foundation::IAsyncOperation<Windows::Networking::Sockets::StreamSocket^> ^op); 
            void startServerRead();
      ref struct AsyncParamsStruct
            {
       Windows::Networking::Sockets::StreamSocketListener^ socketListener;
       Windows::Networking::Sockets::StreamSocket^ stream;
       Windows::Storage::Streams::DataReader^ reader;
            };
     AsyncParamsStruct^ asyncParams;
    [...]

    MainPage.xaml.cpp:
    void Application1::MainPage::UserControl_Loaded(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e)
    {
     txtOut->Text = "LISTENING FOR CLIENT... "; 
     asyncParams = ref new AsyncParamsStruct(); 
     asyncParams->socketListener = ref new StreamSocketListener("192.168.1.69");
     asyncParams->socketListener->ServiceName = "8888";
     auto AcceptOperationSocketListener = asyncParams->socketListener->AcceptAsync();
     AcceptOperationSocketListener->Completed = ref new AsyncOperationCompletedHandler<StreamSocket^>(this, &MainPage::handleLoad);
     AcceptOperationSocketListener->Start();
    }

    void Application1::MainPage::handleLoad(IAsyncOperation<StreamSocket^> ^op)
    {
     if (op->Status == AsyncStatus::Completed)
            {
       txtOut->Text += "CONTACT ESTABLISHED.";
       asyncParams->stream = op->GetResults();
       asyncParams->reader = ref new Windows::Storage::Streams::DataReader(asyncParams->stream->InputStream);
       MainPage::startServerRead();
      }
    }

    void Application1::MainPage::startServerRead()
    {
     // PASSING IN TWO 32 BIT INTEGERS PER UPDATE (x,y)
     auto AcceptOperationServerRead = asyncParams->reader->LoadAsync(8);
     AcceptOperationServerRead->Completed = ref new AsyncOperationCompletedHandler<unsigned int>(
       [this](IAsyncOperation<unsigned int> ^op)
       {
        int xPosition = asyncParams->reader->ReadInt32();
        Canvas::SetTop(testRectangle, (double)xPosition);

        int yPosition = asyncParams->reader->ReadInt32();    
        Canvas::SetLeft(testRectangle, (double)yPosition);

        // RECURSIVE CALL FOR MORE BYTES...
        MainPage::startServerRead();
       });
     AcceptOperationServerRead->Start();
    }

    Hope it helps others,

    • Marked as answer by MEMEOVORE Friday, October 7, 2011 8:04 PM
    Friday, October 7, 2011 8:04 PM