В
первой статье был описан протокол WebSocket, а
во второй процесс установки IIS 8 в операционной системе Windows 8. В данной статье будет показан простой пример использования веб-сокетов в ASP.NET. Для того, чтобы иметь возможность выполнить пример из статьи у себя, нужна будет машина с установленной Windows 8 или Windows Server 2012 с установленными IIS 8 и Visual Studio 2012.
Создаём пустое приложение Web Forms 4.5 в Visual Studio.
После того как проект создан. Добавим в него пустую веб-форму, после следующее содержимое.
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm.aspx.cs"
Inherits="SimpleWeSocketbApplication.WebForm" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title></title>
</head>
<>
<form id="form1" runat="server">
<div>
<span id="webSocketStatusSpan"></span>
<br />
<span id="webSocketReceiveDataSpan"></span>
<br />
<span>Введите строку для отправки</span>
<br />
<input id="nameTextBox" type="text" value="" />
<input type="button" value="Отправить данные" onclick="SendData();" />
<input type="button" value="Закрыть веб-сокет" onclick="CloseWebSocket();" />
</div>
</form>
<script type="text/javascript">
var webSocketStatusSpan = document.getElementById("webSocketStatusSpan");
var webSocketReceiveDataSpan = document.getElementById("webSocketReceiveDataSpan");
var nameTextBox = document.getElementById("nameTextBox");
var webSocket;
//Адрес нашего обработчика HTTP-данных, который будет отвечать на запросы.
var handlerUrl = "ws://localhost/SimpleWebSocketApplication/WebSocketHandler.ashx";
//Метод отправляющий данные.
function SendData() {
//Метод инициализирующий веб-сокет.
InitWebSocket();
//Смотрим, если веб-сокет открыт и готов к использованию
//отправляем данные.
if (webSocket.OPEN && webSocket.readyState == 1)
webSocket.send(nameTextBox.value);
//Если веб-сокет закрывается или закрыт, выводим сообщение.
if (webSocket.readyState == 2 || webSocket.readyState == 3)
webSocketStatusSpan.innerText = "Веб-сокет закрыт, отправить данные невозможно."
}
function CloseWebSocket() {
//Функция для программного закрытия веб-сокета.
//После закрытия, получать или отправлять данные не получится.
webSocket.close();
}
function InitWebSocket() {
//Если объект веб-сокета не инициализирован, инициализируем его.
if (webSocket == undefined) {
webSocket = new WebSocket(handlerUrl);
//Устанавливаем обработчик открытия соединения.
webSocket.onopen = function () {
webSocketStatusSpan.innerText = "Веб-сокет окрыт."
webSocket.send(nameTextBox.value);
};
//Устанавливаем обработчик получения данных.
webSocket.onmessage = function (e) {
webSocketReceiveDataSpan.innerText = e.data;
};
//Устанавливаем обработчик закрытия соединения.
webSocket.onclose = function () {
webSocketStatusSpan.innerText = "Веб-сокет закрыт."
};
//Устанавливаем обработчик ошибки.
webSocket.onerror = function (e) {
webSocketStatusSpan.innerText = e.message;
}
}
}
</script>
</>
</html>
Конечной точкой, обрабатывающей запрос по протоколу WebSocket, на стороне сервера будет обработчик HTTP-данных. Добавим его в наше приложение, а после следующий код.
using System;
using System.Web;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Net.WebSockets;
using System.Web.WebSockets;
namespace SimpleWeSocketbApplication
{
public class WebSocketHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//Проверяем, является ли запрос, запросом по протоколу WebSocket.
if (context.IsWebSocketRequest)
{
//Если да, назначаем асинхронный обработчик.
context.AcceptWebSocketRequest(WebSocketRequestHandler);
}
}
public bool IsReusable { get { return false; } }
//Асинхронный обработчик запроса.
public async Task WebSocketRequestHandler(AspNetWebSocketContext webSocketContext)
{
//Получаем текущий объект веб-сокета.
WebSocket webSocket = webSocketContext.WebSocket;
/*Определяем некую константу, которая будет представлять
максимльный размер входных данных. Её устанавливаем мы и значение
можем задать любым. Мы знаем, что в данном случае размер пересылаемых
данных очень мал.
*/
const int maxMessageSize = 1024;
//Буфер битов, в который будут записываться полученные данные.
ArraySegment<Byte> receivedDataBuffer = new ArraySegment<Byte>(new Byte[maxMessageSize]);
//Токен отмены, в данном примере не используется.
var cancellationToken = new CancellationToken();
//Проверяем состояние веб-сокета.
while (webSocket.State == WebSocketState.Open)
{
//Читаем данные.
WebSocketReceiveResult webSocketReceiveResult =
await webSocket.ReceiveAsync(receivedDataBuffer, cancellationToken);
//Смотрим, если входной фрейм закрывающий, посылаем ответ на закрытие.
if (webSocketReceiveResult.MessageType == WebSocketMessageType.Close)
{
await webSocket.CloseAsync(WebSocketCloseStatus.NormalClosure,
String.Empty, cancellationToken);
}
else
{
//Читаем только те байты, которые пришли.
byte[] payloadData = receivedDataBuffer.Array.Where(b => b != 0).ToArray();
//Поскольку мы знаем, что это строка, то конвертируем.
string receiveString =
System.Text.UTF8Encoding.UTF8.GetString(payloadData, 0, payloadData.Length);
//Собираем новую строку и преобразовываем в массив байт.
var newString =
String.Format("Hello, " + receiveString + " ! Time {0}", DateTime.Now.ToString());
Byte[] bytes = System.Text.UTF8Encoding.UTF8.GetBytes(newString);
//Отсылаем данные обратно браузеру.
await webSocket.SendAsync(new ArraySegment<byte>(bytes),
WebSocketMessageType.Text, true, cancellationToken);
}
}
}
}
}
После того как эти два файла добавлены в проект, устанавливаем локальный IIS 8 в качестве сервера по умолчанию. Хотя использовать IIS 8 Express тоже можно.
Компилируем и запускаем приложение. После того как откроется IE 10, нажимем кнопку "Отправить данные" предварительно введя какое-нибудь слово. Получится примерно следующее:
К сожалению в настоящий момент, кроме Google Chrome, ни один из браузеров не отображет трафик по протоколу WebSocket, в том числе и мой любимый Firefox. Но, думаю, что эта ситуация исправится в близжайшем будущем.
Всё, что было показано выше, демонстрирует работу с протоколом WebSocket в ASP.NET на довольно низком уровне. Специально для этого в сборку System.Web было добавлено новое пространство имён –
System.Web.WebSockets. В следующей статье будет показан более сложный пример показывающий истинные возможности веб-сокетов и демонстрирующий работу с их использованием. Исходный код примеров можно скачать
отсюда.