locked
StreamSocket fails to send data after recieving some

    Question


  • Hello. I have encountered some problems trying to establish two way communication from the client side using StreamSocket.

    I initialize the various objects as follows:

    socket = ref new StreamSocket();
    reader = ref new DataReader(socket->InputStream );
    writer = ref new DataWriter(socket->OutputStream);
    _host= ref new HostName(L"192.168.1.89");
    _port = ref new Platform::String(L"7000");

    and then run the following code. The sequence of operations is the following: connect, receive something from the stream with the DataReader object, and then send some bytes:

    create_task(socket->ConnectAsync(_host, _port)).then([this]()
    {
    receiveFrame(); // Recieves a frame from server, works fine
    std::vector<uint8>*v = VectorOfString("Some String"); // Custom function to make a vector of bytes
    this->writer->WriteBytes(ref new Array<uint8>(v->data(), v->size()));
    return this->writer->StoreAsync();
    }).then([this](unsigned int bytesStored) 
    {
    // At this point, bytesStored is the number of bytes in v
    return this->writer->FlushAsync();
    }).then([this](task<bool> t) {
    try {
    bool connectRes = t.get();
    // Code reaches here ...
    }
    catch ( Exception ^e) {
    // Error
    }
    catch (task_canceled&){
    // Error
    }
    });

    As noted above, the code seems to work fine, shows the right number of bytes after StoreAsync, and throws no exceptions. It seems, however, that the server recieves nothing.
    For reference, the recieveFrame method is included below. It borrows much of its code from this example: 
    http://msdn.microsoft.com/en-us/library/windows/apps/windows.storage.streams.datawriter.aspx?cs-save-lang=1&cs-lang=cpp#code-snippet-2
    I have added some wait() calls, but I don't thik that matters, since this method works fine.

    void DataManager::receiveFrame()
    {

    // Read first 4 bytes (length of the subsequent string).
    task<unsigned int>(reader->LoadAsync(sizeof(UINT32))).then([this] (unsigned int size)
        {
    if (size < sizeof(UINT32))
            {
    // The underlying socket was closed before we were able to read the whole data.
                cancel_current_task();
            }
    OutputDebugString(L"recieveFrame4\n");
            unsigned int stringLength = reader->ReadUInt32();
            return task<unsigned int> (reader->LoadAsync(stringLength)).then([this, stringLength] (unsigned int actualStringLength)
            {
    OutputDebugString(L"recieveFrame5\n");
                if (actualStringLength != stringLength)
                {
                    // The underlying socket was closed before we were able to read the whole data.
                    cancel_current_task();
                }
    // The whole frame was recieved. Make the necessary work
    auto arr = ref new Array<uint8>(actualStringLength);
                this->reader->ReadBytes(arr);
    // Make a vector to give to handleFrame
    auto ret = new std::vector<uint8>();
    ret->resize(actualStringLength);
    for (unsigned int i = 0; i<arr->Length; i++) {
    ret->at(i) = arr[i];
    }
    // Some more synchronous code here...
            }).wait();
        }).wait();
    }

    Any ideas about what's wrong? I am a novice in this async dialect, so maybe I am getting something wrong about that. Or maybe the problem is about initializing both reader and writer on the same socket?
    Thank you for your time!
    Friday, February 08, 2013 12:51 PM

All replies

  • Firstly, You initialized both DataReader and DataWriter  too early.You should initialize them after the connection establish (i.e. after the success of either StreamSocket.ConnectAsync or    StreamSocketListener.ConnectionReceived  asynchronous operation).    

    Secondly, You called receiveFrame() before the completion of ConnectAsync() as it is asynchronous. You should call receiveFrame() function after the connection has been established.

    See the typical order of StreamSocket operations from StreamSocket sample   Description section.

    You can also follow the following code snapped.

    HRESULT  taskResult = S_OK;
    
    create_task(socket->ConnectAsync(remoteAddress, remoteServiceName)).then(
    				[&taskResult] (task<void> previousTask)
    			{
    				try
    				{
    					previousTask.get();   // Success.
    				}
    				catch (Exception^ exception)
    				{
    					taskResult = exception->HResult;    // Failed.
    				}
    			}).get();
    
    if (taskResult == S_OK)
      {
         reader = ref new DataReader(socket->InputStream );
         writer = ref new DataWriter(socket->OutputStream);
         receiveFrame(); // Recieves a frame from server.
      }
    Another important thing, as TCP operates on streams of data (does not operate on packets of data), it is you application's responsibility to maintain the message boundaries. There are two approaches commonly used for message framing: length prefixing and delimiters. Both sender and receiver have to acknowledge in the same  message framing technique. So if you first write the length of the data and then write data(used in the msdn sample), you have to read on the same way.


    Friday, February 08, 2013 2:39 PM
  • Hmmm. I'm afraid I got something wrong with the asynchronous methods.

    I changed the code to:

    HRESULT taskResult = S_OK;
    create_task(socket->ConnectAsync(_host, _port)).then([&taskResult] (task<void> previousTask)
    {
    	try 
    	{
    		previousTask.get();   // Success.
    	}
    	catch (Exception^ exception)
    	{
    		taskResult = exception->HResult;    // Failed.
    	}
    }).get();
    
    if (taskResult == S_OK) 
    {
    	writer = ref new DataWriter(socket->OutputStream);
    	reader = ref new DataReader(socket->InputStream);
    	receiveFrame();
    	auto v = VectorOfString("Some string");		
    	this->writer->WriteBytes(ref new Array<uint8>(v->data(), v->size()));
    	create_task(writer->StoreAsync()).then([this](unsigned int bytesStored) 
    	{
    		return this->writer->FlushAsync();
    	}).then([this](task<bool> t)
    	{
    		try {
    			bool connectRes = t.get();
    			// Execution reaches here
    		}
    		catch ( Exception ^e) {
    			// Failed to send data}			
    		catch (task_canceled&){
    			// Error
    		}
    	});
    }
    else {
    	//something wrong
    }
    

    but it still doesn't work. 

    In your post you say:

    Secondly, You called receiveFrame() before the completion of ConnectAsync() as it is asynchronous.

    But receiveFrame() was called (and still is) inside the lambda parameter of the then() method. Shouldn't that ensure that ConnectAsync() is indeed finished, or I am missing something here?

    Again, thank you for your time.

    Friday, February 08, 2013 9:07 PM
  • Hi,

     

    Would you please upload a sample project which can reproduce this issue?

     

    You can upload it to skydrive, so that we can analyze it deeply.

    https://skydrive.live.com/

     

    Best regards,


    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.

    Monday, February 11, 2013 4:48 AM