This topic shows how to send and receive data using a Windows.Networking.Sockets.MessageWebSocket. This type of WebSocket allows sections of a message to be read with each read operation. A MessageWebSocket is typically used in scenarios where messages are not extremely large. Both UTF-8 and binary files are supported.
The code in this section creates a new MessageWebSocket, connects to a WebSocket server, and sends data to the server. Once a successful connection is established, the app waits for the MessageWebSocket.MessageReceived event to be invoked, indicating that data was received.
This sample uses the WebSocket.org echo server, a service which simply echoes back to the sender any string sent to it. By using the “wss:” protocol specifier, this sample uses a secure connection to send and receive messages.
void Game::InitWebSockets()
{
// Create a new web socket
m_messageWebSocket = ref new MessageWebSocket();
// Set the message type to UTF-8
m_messageWebSocket->Control->MessageType = Windows::Networking::Sockets::SocketMessageType::Utf8;
// Register callbacks for notifications of interest
m_messageWebSocket->MessageReceived += ref new TypedEventHandler<MessageWebSocket^, MessageWebSocketMessageReceivedEventArgs^>(this, &Game:/:WebSocketMessageReceived);
m_messageWebSocket->Closed += ref new TypedEventHandler<IWebSocket^, WebSocketClosedEventArgs^>(this, &Game::WebSocketClosed);
// This test code uses the websocket.org echo service to illustrate sending a string and receiving the echoed string back
// Note that wss: makes this an encrypted connection.
m_serverUri = ref new Uri("wss://echo.websocket.org");
// Establish the connection, and set m_socketConnected on success
create_task(m_messageWebSocket->ConnectAsync(m_serverUri)).then([this] (task<void> previousTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
previousTask.get();
// websocket connected. update state variable
m_socketConnected = true;
OutputDebugString(L"Successfully initialized websockets\n");
}
catch (Platform::COMException^ exception)
{
// Add code here to handle any exceptions
// HandleException(exception);
}
});
}
Once you have initialized the WebSocket connection, your code must perform the following activities to properly send and recieve data.
Before establishing a connection and sending data with a WebSocket, your app needs to register an event callback to receive notification when data is received. When the MessageWebSocket.MessageReceived event occurs, the registered callback is called and receives data from MessageWebSocketMessageReceivedEventArgs. This example is written with the assumption that the messages being sent are in UTF-8 format.
The following sample function receives a string from a connected WebSocket server and prints the string to the debugger output window.
void Game::WebSocketMessageReceived(MessageWebSocket^ sender, MessageWebSocketMessageReceivedEventArgs^ args)
{
DataReader^ messageReader = args->GetDataReader();
messageReader->UnicodeEncoding = Windows::Storage::Streams::UnicodeEncoding::Utf8;
String^ readString = messageReader->ReadString(messageReader->UnconsumedBufferLength);
// Data has been read and is now available from the readString variable.
swprintf(m_debugBuffer, 511, L"WebSocket Message received: %s\n", readString->Data());
OutputDebugString(m_debugBuffer);
}
Before establishing a connection and sending data with a WebSocket, your app needs to register an event callback to receive notification when the WebSocket is closed by the WebSocket server. When the MessageWebSocket.Closed event occurs, the registered callback is called to indicate thet connection was closed by the WebSocket server.
void Game::WebSocketClosed(IWebSocket^ sender, WebSocketClosedEventArgs^ args)
{
// The method may be triggered remotely by the server sending unsolicited close frame or locally by Close()/delete operator.
// This method assumes we saved the connected WebSocket to a variable called m_messageWebSocket
if (m_messageWebSocket != nullptr)
{
delete m_messageWebSocket;
m_messageWebSocket = nullptr;
OutputDebugString(L"Socket was closed\n");
}
m_socketConnected = false;
}
Once a connection is established, the WebSocket client can send data to the server. The DataWriter.StoreAsync method returns a parameter that maps to an unsigned int. This changes how we define the task to send the message compared with the task to make the connection.
Note When you create a new DataWriter object using the MessageWebSocket’s OutputStream, the DataWriter takes ownership of the OutputStream, and will deallocate the Outputstream when the DataWriter goes out of scope. This causes any subsequent attempts to use the OutputStream to fail with an HRESULT value of 0x80000013. To avoid deallocating the OutputStream, this code calls the DataWriter’s DetachStream method, which returns ownership of the stream to the WebSocket object.
The following function sends the given string to a connected WebSocket, and prints a verification message in the debugger output window.
void Game::SendWebSocketMessage(Windows::Networking::Sockets::MessageWebSocket^ sendingSocket, Platform::String^ message)
{
if (m_socketConnected)
{
// WebSocket is connected, so send a message
m_messageWriter = ref new DataWriter(sendingSocket->OutputStream);
m_messageWriter->WriteString(message);
// Send the data as one complete message
create_task(m_messageWriter->StoreAsync()).then([this] (unsigned int)
{
// Send Completed
m_messageWriter->DetachStream(); // give the stream back to m_messageWebSocket
OutputDebugString(L"Sent websocket message\n");
})
.then([this] (task<void>> previousTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
previousTask.get();
}
catch (Platform::COMException ^ex)
{
// Add code to handle the exception
// HandleException(exception);
}
});
}
}