Remarque
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Les WebSockets fournissent un mécanisme permettant une communication rapide, sécurisée et bidirectionnelle entre un client et un serveur sur le web à l’aide de HTTP(S) et prenant en charge les messages UTF-8 et binaires.
Sous le protocole WebSocket, les données sont transférées immédiatement sur une connexion à socket unique duplex complet, ce qui permet aux messages d’être envoyés et reçus des deux points de terminaison en temps réel. Les WebSockets sont idéaux pour les jeux multijoueurs (à la fois en temps réel et au tour par tour), les notifications instantanées sur les réseaux sociaux, les affichages en temps réel des cours de la bourse ou des informations météorologiques actualisées, ainsi que d’autres applications nécessitant un transfert de données sécurisé et rapide.
Pour établir une connexion WebSocket, une liaison http spécifique est échangée entre le client et le serveur. En cas de réussite, le protocole de la couche Application est « mis à niveau » de HTTP vers WebSockets, à l’aide de la connexion TCP établie. Une fois que cela s’est produit, le protocole HTTP disparaît du paysage. Les données peuvent être envoyées ou reçues aux deux points de terminaison via le protocole WebSocket, jusqu’à la fermeture de la connexion WebSocket.
Remarque Un client ne peut pas utiliser webSockets pour transférer des données, sauf si le serveur utilise également le protocole WebSocket. Si le serveur ne prend pas en charge WebSockets, vous devez utiliser une autre méthode de transfert de données.
Windows prend en charge à la fois l’utilisation du client et du serveur de WebSockets. L’espace de noms Windows.Networking.Sockets définit deux classes WebSocket destinées à être utilisées par les clients — MessageWebSocket et StreamWebSocket. Voici une comparaison de ces deux classes WebSocket.
| MessageWebSocket | StreamWebSocket |
|---|---|
| Un message WebSocket entier est lu/écrit en une seule opération. | Les sections d’un message peuvent être lues avec chaque opération de lecture. |
| Convient lorsque les messages ne sont pas très volumineux. | Convient lorsque des fichiers très volumineux (tels que des photos ou des vidéos) sont transférés. |
| Prend en charge les messages UTF-8 et binaires. | Prend uniquement en charge les messages binaires. |
| Similaire à un socket UDP ou datagram (au sens d’être destiné à des messages fréquents, petits), mais avec la fiabilité de TCP, les garanties d’ordre des paquets et le contrôle de congestion. | Semblable à un socket TCP ou socket de flux. |
Sécuriser votre connexion avec TLS/SSL
Dans la plupart des cas, vous souhaiterez utiliser une connexion WebSocket sécurisée afin que les données que vous envoyez et recevez soient chiffrées. Cela augmente également les chances que votre connexion réussisse, car de nombreux intermédiaires tels que les pare-feu et les proxys rejettent les connexions WebSocket non chiffrées. Le protocole WebSocket définit ces deux schémas d’URI.
| Schéma d’URI | Purpose |
|---|---|
| wss : | Utiliser pour les connexions sécurisées qui doivent être chiffrées. |
| Ws: | Utiliser pour les connexions non chiffrées. |
Pour chiffrer votre connexion WebSocket, utilisez le schéma d’URI wss: . Voici un exemple.
protected override async void OnNavigatedTo(NavigationEventArgs e)
{
var webSocket = new Windows.Networking.Sockets.MessageWebSocket();
await webSocket.ConnectAsync(new Uri("wss://www.contoso.com/mywebservice"));
}
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Networking.Sockets.h>
#include <sstream>
using namespace winrt;
using namespace Windows::Foundation;
...
IAsyncAction ConnectWebSocketAsync()
{
Windows::Networking::Sockets::MessageWebSocket webSocket;
co_await webSocket.ConnectAsync(Uri{ L"wss://www.contoso.com/mywebservice" });
}
Utiliser MessageWebSocket pour se connecter
MessageWebSocket permet à un message WebSocket entier d’être lu/écrit en une seule opération. Par conséquent, il convient lorsque les messages ne sont pas très volumineux. La classe prend en charge les messages UTF-8 et binaires.
L’exemple de code ci-dessous se connecte à un serveur WebSocket et envoie un message. Le service public echo.websocket.org est supprimé. Remplacez l’URI d’espace réservé dans ces exemples par votre propre URI de serveur WebSocket.
private Windows.Networking.Sockets.MessageWebSocket messageWebSocket;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.messageWebSocket = new Windows.Networking.Sockets.MessageWebSocket();
// In this example, we send/receive a string, so we need to set the MessageType to Utf8.
this.messageWebSocket.Control.MessageType = Windows.Networking.Sockets.SocketMessageType.Utf8;
this.messageWebSocket.MessageReceived += WebSocket_MessageReceived;
this.messageWebSocket.Closed += WebSocket_Closed;
try
{
// Replace with your WebSocket server URI.
Task connectTask = this.messageWebSocket.ConnectAsync(new Uri("wss://example.com/ws")).AsTask();
connectTask.ContinueWith(_ => this.SendMessageUsingMessageWebSocketAsync("Hello, World!"));
}
catch (Exception ex)
{
Windows.Web.WebErrorStatus webErrorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add additional code here to handle exceptions.
}
}
private async Task SendMessageUsingMessageWebSocketAsync(string message)
{
using (var dataWriter = new DataWriter(this.messageWebSocket.OutputStream))
{
dataWriter.WriteString(message);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
Debug.WriteLine("Sending message using MessageWebSocket: " + message);
}
private void WebSocket_MessageReceived(Windows.Networking.Sockets.MessageWebSocket sender, Windows.Networking.Sockets.MessageWebSocketMessageReceivedEventArgs args)
{
try
{
using (DataReader dataReader = args.GetDataReader())
{
dataReader.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf8;
string message = dataReader.ReadString(dataReader.UnconsumedBufferLength);
Debug.WriteLine("Message received from MessageWebSocket: " + message);
this.messageWebSocket.Dispose();
}
}
catch (Exception ex)
{
Windows.Web.WebErrorStatus webErrorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add additional code here to handle exceptions.
}
}
private void WebSocket_Closed(Windows.Networking.Sockets.IWebSocket sender, Windows.Networking.Sockets.WebSocketClosedEventArgs args)
{
Debug.WriteLine("WebSocket_Closed; Code: " + args.Code + ", Reason: \"" + args.Reason + "\"");
// Add additional code here to handle the WebSocket being closed.
}
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Networking.Sockets.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Microsoft.UI.Xaml.Navigation.h>
#include <sstream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Xaml::Navigation;
...
private:
Windows::Networking::Sockets::MessageWebSocket m_messageWebSocket;
winrt::event_token m_messageReceivedEventToken;
winrt::event_token m_closedEventToken;
public:
IAsyncAction OnNavigatedTo(NavigationEventArgs /* e */)
{
// In this example, we send/receive a string, so we need to set the MessageType to Utf8.
m_messageWebSocket.Control().MessageType(Windows::Networking::Sockets::SocketMessageType::Utf8);
m_messageReceivedEventToken = m_messageWebSocket.MessageReceived({ this, &MessageWebSocketPage::OnWebSocketMessageReceived });
m_closedEventToken = m_messageWebSocket.Closed({ this, &MessageWebSocketPage::OnWebSocketClosed });
try
{
co_await m_messageWebSocket.ConnectAsync(Uri{ L"wss://example.com/ws" });
SendMessageUsingMessageWebSocketAsync(L"Hello, World!");
}
catch (winrt::hresult_error const& ex)
{
Windows::Web::WebErrorStatus webErrorStatus{ Windows::Networking::Sockets::WebSocketError::GetStatus(ex.to_abi()) };
// Add additional code here to handle exceptions.
}
}
private:
IAsyncAction SendMessageUsingMessageWebSocketAsync(std::wstring message)
{
DataWriter dataWriter{ m_messageWebSocket.OutputStream() };
dataWriter.WriteString(message);
co_await dataWriter.StoreAsync();
dataWriter.DetachStream();
std::wstringstream wstringstream;
wstringstream << L"Sending message using MessageWebSocket: " << message.c_str() << std::endl;
::OutputDebugString(wstringstream.str().c_str());
}
void OnWebSocketMessageReceived(Windows::Networking::Sockets::MessageWebSocket const& /* sender */, Windows::Networking::Sockets::MessageWebSocketMessageReceivedEventArgs const& args)
{
try
{
DataReader dataReader{ args.GetDataReader() };
dataReader.UnicodeEncoding(Windows::Storage::Streams::UnicodeEncoding::Utf8);
auto message = dataReader.ReadString(dataReader.UnconsumedBufferLength());
std::wstringstream wstringstream;
wstringstream << L"Message received from MessageWebSocket: " << message.c_str() << std::endl;
::OutputDebugString(wstringstream.str().c_str());
m_messageWebSocket.Close(1000, L"");
}
catch (winrt::hresult_error const& ex)
{
Windows::Web::WebErrorStatus webErrorStatus{ Windows::Networking::Sockets::WebSocketError::GetStatus(ex.to_abi()) };
// Add additional code here to handle exceptions.
}
}
void OnWebSocketClosed(Windows::Networking::Sockets::IWebSocket const& /* sender */, Windows::Networking::Sockets::WebSocketClosedEventArgs const& args)
{
std::wstringstream wstringstream;
wstringstream << L"WebSocket_Closed; Code: " << args.Code() << ", Reason: \"" << args.Reason().c_str() << "\"" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
// Add additional code here to handle the WebSocket being closed.
}
#include <ppltasks.h>
#include <sstream>
...
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Xaml::Navigation;
...
private:
Windows::Networking::Sockets::MessageWebSocket^ messageWebSocket;
protected:
virtual void OnNavigatedTo(NavigationEventArgs^ e) override
{
this->messageWebSocket = ref new Windows::Networking::Sockets::MessageWebSocket();
// In this example, we send/receive a string, so we need to set the MessageType to Utf8.
this->messageWebSocket->Control->MessageType = Windows::Networking::Sockets::SocketMessageType::Utf8;
this->messageWebSocket->MessageReceived += ref new TypedEventHandler<Windows::Networking::Sockets::MessageWebSocket^, Windows::Networking::Sockets::MessageWebSocketMessageReceivedEventArgs^>(this, &MessageWebSocketPage::WebSocket_MessageReceived);
this->messageWebSocket->Closed += ref new TypedEventHandler<Windows::Networking::Sockets::IWebSocket^, Windows::Networking::Sockets::WebSocketClosedEventArgs^>(this, &MessageWebSocketPage::WebSocket_Closed);
try
{
auto connectTask = Concurrency::create_task(this->messageWebSocket->ConnectAsync(ref new Uri(L"wss://example.com/ws")));
connectTask.then([this] { this->SendMessageUsingMessageWebSocketAsync(L"Hello, World!"); });
}
catch (Platform::Exception^ ex)
{
Windows::Web::WebErrorStatus webErrorStatus = Windows::Networking::Sockets::WebSocketError::GetStatus(ex->HResult);
// Add additional code here to handle exceptions.
}
}
private:
void SendMessageUsingMessageWebSocketAsync(Platform::String^ message)
{
auto dataWriter = ref new DataWriter(this->messageWebSocket->OutputStream);
dataWriter->WriteString(message);
Concurrency::create_task(dataWriter->StoreAsync()).then(
[=](unsigned int)
{
dataWriter->DetachStream();
std::wstringstream wstringstream;
wstringstream << L"Sending message using MessageWebSocket: " << message->Data() << std::endl;
::OutputDebugString(wstringstream.str().c_str());
});
}
void WebSocket_MessageReceived(Windows::Networking::Sockets::MessageWebSocket^ sender, Windows::Networking::Sockets::MessageWebSocketMessageReceivedEventArgs^ args)
{
try
{
DataReader^ dataReader = args->GetDataReader();
dataReader->UnicodeEncoding = Windows::Storage::Streams::UnicodeEncoding::Utf8;
Platform::String^ message = dataReader->ReadString(dataReader->UnconsumedBufferLength);
std::wstringstream wstringstream;
wstringstream << L"Message received from MessageWebSocket: " << message->Data() << std::endl;
::OutputDebugString(wstringstream.str().c_str());
this->messageWebSocket->Close(1000, L"");
}
catch (Platform::Exception^ ex)
{
Windows::Web::WebErrorStatus webErrorStatus = Windows::Networking::Sockets::WebSocketError::GetStatus(ex->HResult);
// Add additional code here to handle exceptions.
}
}
void WebSocket_Closed(Windows::Networking::Sockets::IWebSocket^ sender, Windows::Networking::Sockets::WebSocketClosedEventArgs^ args)
{
std::wstringstream wstringstream;
wstringstream << L"WebSocket_Closed; Code: " << args->Code << ", Reason: \"" << args->Reason->Data() << "\"" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
// Add additional code here to handle the WebSocket being closed.
}
Gérer les événements MessageWebSocket.MessageReceived et MessageWebSocket.Closed
Comme indiqué dans l’exemple ci-dessus, avant d’établir une connexion et d’envoyer des données avec un MessageWebSocket, vous devez vous abonner aux événements MessageWebSocket.MessageReceived et MessageWebSocket.Closed .
MessageReceived est déclenché lorsque les données sont reçues. Les données sont accessibles via MessageWebSocketMessageReceivedEventArgs. Fermé est déclenché lorsque le client ou le serveur ferme le socket.
Envoyer des données sur un MessageWebSocket
Une fois qu’une connexion est établie, vous pouvez envoyer des données au serveur. Pour écrire les données, procédez ainsi à l’aide de la propriété MessageWebSocket.OutputStream et d’un DataWriter.
NoteDataWriter prend possession du flux de sortie. Lorsque DataWriter est hors de portée, si le flux de sortie est attaché à celui-ci, DataWriter désalloue le flux de sortie. Après cela, les tentatives suivantes d’utilisation du flux de sortie échouent avec une valeur HRESULT de 0x80000013. Toutefois, vous pouvez appeler DataWriter.DetachStream pour détacher le flux de sortie de DataWriter et renvoyer la propriété du flux au MessageWebSocket.
Utiliser StreamWebSocket pour se connecter
StreamWebSocket permet de lire des sections d’un message avec chaque opération de lecture. Par conséquent, il convient quand des fichiers très volumineux (tels que des photos ou des vidéos) sont transférés. La classe prend uniquement en charge les messages binaires.
L’exemple de code ci-dessous se connecte à un serveur WebSocket et envoie un message. Le service public echo.websocket.org est supprimé. Ces exemples utilisent donc également un URI d’espace réservé que vous devez remplacer par votre propre URI de serveur WebSocket.
private Windows.Networking.Sockets.StreamWebSocket streamWebSocket;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.streamWebSocket = new Windows.Networking.Sockets.StreamWebSocket();
this.streamWebSocket.Closed += WebSocket_Closed;
try
{
Task connectTask = this.streamWebSocket.ConnectAsync(new Uri("wss://example.com/ws")).AsTask();
connectTask.ContinueWith(_ =>
{
Task.Run(() => this.ReceiveMessageUsingStreamWebSocket());
Task.Run(() => this.SendMessageUsingStreamWebSocket(new byte[] { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 }));
});
}
catch (Exception ex)
{
Windows.Web.WebErrorStatus webErrorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add code here to handle exceptions.
}
}
private async void ReceiveMessageUsingStreamWebSocket()
{
try
{
using (var dataReader = new DataReader(this.streamWebSocket.InputStream))
{
dataReader.InputStreamOptions = InputStreamOptions.Partial;
await dataReader.LoadAsync(256);
byte[] message = new byte[dataReader.UnconsumedBufferLength];
dataReader.ReadBytes(message);
Debug.WriteLine("Data received from StreamWebSocket: " + message.Length + " bytes");
}
this.streamWebSocket.Dispose();
}
catch (Exception ex)
{
Windows.Web.WebErrorStatus webErrorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add code here to handle exceptions.
}
}
private async void SendMessageUsingStreamWebSocket(byte[] message)
{
try
{
using (var dataWriter = new DataWriter(this.streamWebSocket.OutputStream))
{
dataWriter.WriteBytes(message);
await dataWriter.StoreAsync();
dataWriter.DetachStream();
}
Debug.WriteLine("Sending data using StreamWebSocket: " + message.Length.ToString() + " bytes");
}
catch (Exception ex)
{
Windows.Web.WebErrorStatus webErrorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add code here to handle exceptions.
}
}
private void WebSocket_Closed(Windows.Networking.Sockets.IWebSocket sender, Windows.Networking.Sockets.WebSocketClosedEventArgs args)
{
Debug.WriteLine("WebSocket_Closed; Code: " + args.Code + ", Reason: \"" + args.Reason + "\"");
// Add additional code here to handle the WebSocket being closed.
}
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Networking.Sockets.h>
#include <winrt/Windows.Storage.Streams.h>
#include <winrt/Microsoft.UI.Xaml.Navigation.h>
#include <sstream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Xaml::Navigation;
...
private:
Windows::Networking::Sockets::StreamWebSocket m_streamWebSocket;
winrt::event_token m_closedEventToken;
public:
IAsyncAction OnNavigatedTo(NavigationEventArgs /* e */)
{
m_closedEventToken = m_streamWebSocket.Closed({ this, &StreamWebSocketPage::OnWebSocketClosed });
try
{
co_await m_streamWebSocket.ConnectAsync(Uri{ L"wss://example.com/ws" });
ReceiveMessageUsingStreamWebSocket();
SendMessageUsingStreamWebSocket({ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 });
}
catch (winrt::hresult_error const& ex)
{
Windows::Web::WebErrorStatus webErrorStatus{ Windows::Networking::Sockets::WebSocketError::GetStatus(ex.to_abi()) };
// Add additional code here to handle exceptions.
}
}
private:
IAsyncAction SendMessageUsingStreamWebSocket(std::vector< byte > message)
{
try
{
DataWriter dataWriter{ m_streamWebSocket.OutputStream() };
dataWriter.WriteBytes(message);
co_await dataWriter.StoreAsync();
dataWriter.DetachStream();
std::wstringstream wstringstream;
wstringstream << L"Sending data using StreamWebSocket: " << message.size() << L" bytes" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
}
catch (winrt::hresult_error const& ex)
{
Windows::Web::WebErrorStatus webErrorStatus{ Windows::Networking::Sockets::WebSocketError::GetStatus(ex.to_abi()) };
// Add additional code here to handle exceptions.
}
}
IAsyncAction ReceiveMessageUsingStreamWebSocket()
{
try
{
DataReader dataReader{ m_streamWebSocket.InputStream() };
dataReader.InputStreamOptions(InputStreamOptions::Partial);
unsigned int bytesLoaded = co_await dataReader.LoadAsync(256);
std::vector< byte > message(bytesLoaded);
dataReader.ReadBytes(message);
std::wstringstream wstringstream;
wstringstream << L"Data received from StreamWebSocket: " << message.size() << " bytes" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
m_streamWebSocket.Close(1000, L"");
}
catch (winrt::hresult_error const& ex)
{
Windows::Web::WebErrorStatus webErrorStatus{ Windows::Networking::Sockets::WebSocketError::GetStatus(ex.to_abi()) };
// Add additional code here to handle exceptions.
}
}
void OnWebSocketClosed(Windows::Networking::Sockets::IWebSocket const&, Windows::Networking::Sockets::WebSocketClosedEventArgs const& args)
{
std::wstringstream wstringstream;
wstringstream << L"WebSocket_Closed; Code: " << args.Code() << ", Reason: \"" << args.Reason().c_str() << "\"" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
// Add additional code here to handle the WebSocket being closed.
}
#include <ppltasks.h>
#include <sstream>
...
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Xaml::Navigation;
...
private:
Windows::Networking::Sockets::StreamWebSocket^ streamWebSocket;
protected:
virtual void OnNavigatedTo(NavigationEventArgs^ e) override
{
this->streamWebSocket = ref new Windows::Networking::Sockets::StreamWebSocket();
this->streamWebSocket->Closed += ref new TypedEventHandler<Windows::Networking::Sockets::IWebSocket^, Windows::Networking::Sockets::WebSocketClosedEventArgs^>(this, &StreamWebSocketPage::WebSocket_Closed);
try
{
auto connectTask = Concurrency::create_task(this->streamWebSocket->ConnectAsync(ref new Uri(L"wss://example.com/ws")));
connectTask.then(
[=]
{
this->ReceiveMessageUsingStreamWebSocket();
this->SendMessageUsingStreamWebSocket(ref new Platform::Array< byte >{ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09 });
});
}
catch (Platform::Exception^ ex)
{
Windows::Web::WebErrorStatus webErrorStatus = Windows::Networking::Sockets::WebSocketError::GetStatus(ex->HResult);
// Add additional code here to handle exceptions.
}
}
private:
void SendMessageUsingStreamWebSocket(const Platform::Array< byte >^ message)
{
try
{
auto dataWriter = ref new DataWriter(this->streamWebSocket->OutputStream);
dataWriter->WriteBytes(message);
Concurrency::create_task(dataWriter->StoreAsync()).then(
[=](Concurrency::task< unsigned int >) // task< unsigned int > instead of unsigned int in order to handle any exceptions thrown in StoreAsync().
{
dataWriter->DetachStream();
std::wstringstream wstringstream;
wstringstream << L"Sending data using StreamWebSocket: " << message->Length << L" bytes" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
});
}
catch (Platform::Exception^ ex)
{
Windows::Web::WebErrorStatus webErrorStatus = Windows::Networking::Sockets::WebSocketError::GetStatus(ex->HResult);
// Add additional code here to handle exceptions.
}
}
void ReceiveMessageUsingStreamWebSocket()
{
try
{
DataReader^ dataReader = ref new DataReader(this->streamWebSocket->InputStream);
dataReader->InputStreamOptions = InputStreamOptions::Partial;
Concurrency::create_task(dataReader->LoadAsync(256)).then(
[=](unsigned int bytesLoaded)
{
auto message = ref new Platform::Array< byte >(bytesLoaded);
dataReader->ReadBytes(message);
std::wstringstream wstringstream;
wstringstream << L"Data received from StreamWebSocket: " << message->Length << " bytes" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
this->streamWebSocket->Close(1000, L"");
});
}
catch (Platform::Exception^ ex)
{
Windows::Web::WebErrorStatus webErrorStatus = Windows::Networking::Sockets::WebSocketError::GetStatus(ex->HResult);
// Add additional code here to handle exceptions.
}
}
void WebSocket_Closed(Windows::Networking::Sockets::IWebSocket^ sender, Windows::Networking::Sockets::WebSocketClosedEventArgs^ args)
{
std::wstringstream wstringstream;
wstringstream << L"WebSocket_Closed; Code: " << args->Code << ", Reason: \"" << args->Reason->Data() << "\"" << std::endl;
::OutputDebugString(wstringstream.str().c_str());
// Add additional code here to handle the WebSocket being closed.
}
Gérer l’événement StreamWebSocket.Closed
Avant d’établir une connexion et d’envoyer des données avec un StreamWebSocket, vous devez vous abonner à l’événement StreamWebSocket.Closed . Fermé est déclenché lorsque le client ou le serveur ferme le socket.
Envoyer des données sur un StreamWebSocket
Une fois qu’une connexion est établie, vous pouvez envoyer des données au serveur. Pour écrire les données, procédez ainsi à l’aide de la propriété StreamWebSocket.OutputStream et d’un DataWriter.
Remarque Si vous souhaitez écrire plus de données sur le même socket, veillez à appeler DataWriter.DetachStream pour détacher le flux de sortie de DataWriter avant que DataWriter ne soit hors de portée. Cela retourne la propriété du flux vers StreamWebSocket.
Recevoir des données sur un StreamWebSocket
Utilisez la propriété StreamWebSocket.InputStream et un DataReader pour lire les données.
Options avancées pour MessageWebSocket et StreamWebSocket
Avant d’établir une connexion, vous pouvez définir des options avancées sur un socket en définissant des propriétés sur MessageWebSocketControl ou StreamWebSocketControl. Vous accédez à une instance de ces classes à partir de l’objet socket lui-même via sa propriété MessageWebSocket.Control ou sa propriété StreamWebSocket.Control , le cas échéant.
Voici un exemple utilisant StreamWebSocket. Le même modèle s’applique à MessageWebSocket.
var streamWebSocket = new Windows.Networking.Sockets.StreamWebSocket();
// By default, the Nagle algorithm is not used. This overrides that, and causes it to be used.
streamWebSocket.Control.NoDelay = false;
await streamWebSocket.ConnectAsync(new Uri("wss://example.com/ws"));
Windows::Networking::Sockets::StreamWebSocket streamWebSocket;
// By default, the Nagle algorithm is not used. This overrides that, and causes it to be used.
streamWebSocket.Control().NoDelay(false);
auto connectAsyncAction = streamWebSocket.ConnectAsync(Uri{ L"wss://example.com/ws" });
auto streamWebSocket = ref new Windows::Networking::Sockets::StreamWebSocket();
// By default, the Nagle algorithm is not used. This overrides that, and causes it to be used.
streamWebSocket->Control->NoDelay = false;
auto connectTask = Concurrency::create_task(streamWebSocket->ConnectAsync(ref new Uri(L"wss://example.com/ws")));
Note N’essayez pas de modifier une propriété de contrôle après avoir appelé ConnectAsync. La seule exception à cette règle est MessageWebSocketControl.MessageType.
Classes d’informations WebSocket
MessageWebSocket et StreamWebSocket ont chacun une classe correspondante qui fournit des informations supplémentaires sur l’objet.
MessageWebSocketInformation fournit des informations sur un MessageWebSocket et vous récupérez une instance de celle-ci à l’aide de la propriété MessageWebSocket.Information .
StreamWebSocketInformation fournit des informations sur un StreamWebSocket et vous récupérez une instance de celle-ci à l’aide de la propriété StreamWebSocket.Information .
Notez que les propriétés de ces classes d’informations sont en lecture seule, mais vous pouvez les utiliser pour récupérer des informations à tout moment pendant la durée de vie d’un objet de socket web.
Gestion des exceptions
Une erreur rencontrée sur une opération MessageWebSocket ou StreamWebSocket est retournée en tant que valeur HRESULT . Vous pouvez transmettre cette valeur HRESULT à la méthode WebSocketError.GetStatus pour la convertir en valeur d’énumération WebErrorStatus .
La plupart des valeurs d’énumération WebErrorStatus correspondent à une erreur retournée par l’opération de client HTTP native. Votre application peut activer les valeurs d’énumération WebErrorStatus pour modifier le comportement de l’application en fonction de la cause de l’exception.
Pour les erreurs de validation de paramètre, vous pouvez utiliser HRESULT à partir de l’exception pour en savoir plus sur l’erreur. Les valeurs HRESULT possibles sont répertoriées Winerror.hdans , qui se trouvent dans votre installation du Kit de développement logiciel (SDK) (par exemple, dans le dossier C:\Program Files (x86)\Windows Kits\10\Include\<VERSION>\shared). Pour la plupart des erreurs de validation de paramètre, HRESULT retourné est E_INVALIDARG.
Configuration des délais d’expiration pour les opérations WebSocket
MessageWebSocket et StreamWebSocket utilisent un service système interne pour envoyer des demandes de client WebSocket et recevoir des réponses d’un serveur. La valeur de délai d’expiration par défaut utilisée pour une opération de connexion WebSocket est de 60 secondes. Si le serveur HTTP qui prend en charge WebSockets ne répond pas ou ne peut pas répondre à la demande de connexion WebSocket (il est temporairement arrêté ou bloqué par une panne réseau), le service système interne attend les 60 secondes par défaut avant de renvoyer une erreur. Cette erreur entraîne le déclenchement d’une exception dans la méthode WebSocket ConnectAsync. Pour les opérations d’envoi et de réception après l’établissement d’une connexion WebSocket, le délai d’expiration par défaut est de 30 secondes.
Si la requête de nom d’un nom de serveur HTTP dans l’URI retourne plusieurs adresses IP pour le nom, le service système interne tente jusqu’à 5 adresses IP pour le site (chacune avec un délai d’expiration par défaut de 60 secondes) avant d’échouer. Par conséquent, votre application peut attendre plusieurs minutes en essayant de se connecter à plusieurs adresses IP avant de gérer une exception. Ce comportement peut sembler à l’utilisateur comme l’application a cessé de fonctionner.
Pour rendre votre application plus réactive et réduire ces problèmes, vous pouvez définir un délai d’expiration plus court sur les demandes de connexion. Vous définissez un délai d’expiration de la même façon pour MessageWebSocket et StreamWebSocket.
private Windows.Networking.Sockets.MessageWebSocket messageWebSocket;
protected override void OnNavigatedTo(NavigationEventArgs e)
{
this.messageWebSocket = new Windows.Networking.Sockets.MessageWebSocket();
try
{
var cancellationTokenSource = new CancellationTokenSource();
var connectTask = this.messageWebSocket.ConnectAsync(new Uri("wss://example.com/ws")).AsTask(cancellationTokenSource.Token);
// Cancel connectTask after 5 seconds.
cancellationTokenSource.CancelAfter(TimeSpan.FromMilliseconds(5000));
connectTask.ContinueWith((antecedent) =>
{
if (antecedent.Status == TaskStatus.RanToCompletion)
{
// connectTask ran to completion, so we know that the MessageWebSocket is connected.
// Add additional code here to use the MessageWebSocket.
}
else
{
// connectTask timed out, or faulted.
}
});
}
catch (Exception ex)
{
Windows.Web.WebErrorStatus webErrorStatus = Windows.Networking.Sockets.WebSocketError.GetStatus(ex.GetBaseException().HResult);
// Add additional code here to handle exceptions.
}
}
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Networking.Sockets.h>
#include <winrt/Microsoft.UI.Xaml.Navigation.h>
#include <sstream>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::UI::Xaml::Navigation;
...
private:
Windows::Networking::Sockets::MessageWebSocket m_messageWebSocket;
IAsyncAction TimeoutAsync()
{
// Return control to the caller, and resume again to complete the async action after the timeout period.
// 5 seconds, in this example.
co_await(std::chrono::seconds{ 5 });
}
public:
IAsyncAction OnNavigatedTo(NavigationEventArgs /* e */)
{
try
{
// Return control to the caller, and then immediately resume on a thread pool thread.
co_await winrt::resume_background();
auto connectAsyncAction = m_messageWebSocket.ConnectAsync(Uri{ L"wss://example.com/ws" });
TimeoutAsync().Completed([connectAsyncAction](IAsyncAction const& sender, AsyncStatus const)
{
// TimeoutAsync completes after the timeout period. After that period, it's safe
// to cancel the ConnectAsync action even if it has already completed.
connectAsyncAction.Cancel();
});
try
{
// Block until the ConnectAsync action completes or is canceled.
connectAsyncAction.get();
}
catch (winrt::hresult_error const& ex)
{
std::wstringstream wstringstream;
wstringstream << L"ConnectAsync threw an exception: " << ex.message().c_str() << std::endl;
::OutputDebugString(wstringstream.str().c_str());
}
if (connectAsyncAction.Status() == AsyncStatus::Completed)
{
// connectTask ran to completion, so we know that the MessageWebSocket is connected.
// Add additional code here to use the MessageWebSocket.
}
else
{
// connectTask did not run to completion.
}
}
catch (winrt::hresult_error const& ex)
{
Windows::Web::WebErrorStatus webErrorStatus{ Windows::Networking::Sockets::WebSocketError::GetStatus(ex.to_abi()) };
// Add additional code here to handle exceptions.
}
}
#include <agents.h>
#include <ppltasks.h>
#include <sstream>
...
using namespace Windows::Foundation;
using namespace Windows::Storage::Streams;
using namespace Windows::UI::Xaml::Navigation;
...
private:
Windows::Networking::Sockets::MessageWebSocket^ messageWebSocket;
protected:
virtual void OnNavigatedTo(NavigationEventArgs^ e) override
{
this->messageWebSocket = ref new Windows::Networking::Sockets::MessageWebSocket();
try
{
Concurrency::cancellation_token_source cancellationTokenSource;
Concurrency::cancellation_token cancellationToken = cancellationTokenSource.get_token();
auto connectTask = Concurrency::create_task(this->messageWebSocket->ConnectAsync(ref new Uri(L"wss://example.com/ws")), cancellationToken);
// This continuation task returns true should connectTask run to completion.
Concurrency::task< bool > taskRanToCompletion = connectTask.then([](void)
{
return true;
});
// This task returns false after the specified timeout. 5 seconds, in this example.
Concurrency::task< bool > taskTimedout = Concurrency::create_task([]() -> bool
{
Concurrency::task_completion_event< void > taskCompletionEvent;
// A call object that sets the task completion event.
auto call = std::make_shared< Concurrency::call< int > >([taskCompletionEvent](int)
{
taskCompletionEvent.set();
});
// A non-repeating timer that calls the call object when the timer fires.
auto nonRepeatingTimer = std::make_shared< Concurrency::timer < int > >(5000, 0, call.get(), false);
nonRepeatingTimer->start();
// A task that completes after the completion event is set.
Concurrency::task< void > taskWaitForCompletionEvent(taskCompletionEvent);
return taskWaitForCompletionEvent.then([]() {return false; }).get();
});
(taskRanToCompletion || taskTimedout).then([this, cancellationTokenSource](bool connectTaskRanToCompletion)
{
if (connectTaskRanToCompletion)
{
// connectTask ran to completion, so we know that the MessageWebSocket is connected.
// Add additional code here to use the MessageWebSocket.
}
else
{
// taskTimedout ran to completion, so we should cancel connectTask via the cancellation_token_source.
cancellationTokenSource.cancel();
}
});
}
catch (Platform::Exception^ ex)
{
Windows::Web::WebErrorStatus webErrorStatus = Windows::Networking::Sockets::WebSocketError::GetStatus(ex->HResult);
// Add additional code here to handle exceptions.
}
}
API importantes
- DataReader
- DataWriter
- DataWriter.DetachStream
- MessageWebSocket
- MessageWebSocket.Closed
- MessageWebSocket.ConnectAsync
- MessageWebSocket.Control
- MessageWebSocket.Information
- MessageWebSocket.MessageReceived
- MessageWebSocket.OutputStream
- MessageWebSocketControl
- MessageWebSocketControl.MessageType
- MessageWebSocketInformation
- MessageWebSocketMessageReceivedEventArgs
- SocketMessageType
- StreamWebSocket
- StreamWebSocket.Closed
- StreamSocket.ConnectAsync
- StreamWebSocket.Control
- StreamWebSocket.Information
- StreamWebSocket.InputStream
- StreamWebSocket.OutputStream
- StreamWebSocketControl
- StreamWebSocketInformation
- WebErrorStatus
- WebSocketError.GetStatus
- Windows.Networking.Sockets
Rubriques connexes
Samples
Windows developer