Вступление
Я думаю, что многие веб-разработчики задают себе вопрос о том, как передать пользователю какое-либо сообщение, напоминание. Раньше для этого было необходимо постоянно отправлять запросы к веб-серверу, но теперь появилась такая удобная технология, как Web Socket.
В этой статье я хочу показать, как можно написать простой чат на ASP.NET MVC 4 с помощью Web Socket.
Приступаем
Для начала нам необходимо создать пустой проект ASP.NET MVC 4
И добавить в него универсальный обработчик ChatHandler
Теперь изменим код метода ProcessRequest нашего обработчика на
public void ProcessRequest(HttpContext context)
{
//Если запрос является запросом веб сокета
if (context.IsWebSocketRequest)
context.AcceptWebSocketRequest(WebSocketRequest);
}
Добавим 2 переменные
// Список всех клиентов
private static readonly List<WebSocket> Clients = new List<WebSocket>();
// Блокировка для обеспечения потокабезопасности
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
И напишем основной метод нашего чата
private async Task WebSocketRequest(AspNetWebSocketContext context)
{
// Получаем сокет клиента из контекста запроса
var socket = context.WebSocket;
// Добавляем его в список клиентов
Locker.EnterWriteLock();
try
{
Clients.Add(socket);
}
finally
{
Locker.ExitWriteLock();
}
// Слушаем его
while (true)
{
var buffer = new ArraySegment<byte>(new byte[1024]);
// Ожидаем данные от него
var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
//Передаём сообщение всем клиентам
for (int i = 0; i < Clients.Count; i++)
{
WebSocket client = Clients[i];
try
{
if (client.State == WebSocketState.Open)
{
await client.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
}
catch (ObjectDisposedException)
{
Locker.EnterWriteLock();
try
{
Clients.Remove(client);
i--;
}
finally
{
Locker.ExitWriteLock();
}
}
}
}
}
Теперь наш обработчик должен выглядеть так:
public class ChatHandler : IHttpHandler
{
// Список всех клиентов
private static readonly List<WebSocket> Clients = new List<WebSocket>();
// Блокировка для обеспечения потокабезопасности
private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();
public void ProcessRequest(HttpContext context)
{
//Если запрос является запросом веб сокета
if (context.IsWebSocketRequest)
context.AcceptWebSocketRequest(WebSocketRequest);
}
private async Task WebSocketRequest(AspNetWebSocketContext context)
{
// Получаем сокет клиента из контекста запроса
var socket = context.WebSocket;
// Добавляем его в список клиентов
Locker.EnterWriteLock();
try
{
Clients.Add(socket);
}
finally
{
Locker.ExitWriteLock();
}
// Слушаем его
while (true)
{
var buffer = new ArraySegment<byte>(new byte[1024]);
// Ожидаем данные от него
var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
//Передаём сообщение всем клиентам
for (int i = 0; i < Clients.Count; i++)
{
WebSocket client = Clients[i];
try
{
if (client.State == WebSocketState.Open)
{
await client.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
}
}
catch (ObjectDisposedException)
{
Locker.EnterWriteLock();
try
{
Clients.Remove(client);
i--;
}
finally
{
Locker.ExitWriteLock();
}
}
}
}
}
public bool IsReusable
{
get
{
return false;
}
}
}
Теперь мы можем написать простенькую html страничку, которая будет содержать Web Socket, подключающийся к нашему обработчику
<!DOCTYPE html>
<html>
<head>
<title>Простой чат</title>
</head>
<body>
<input type="text" id="user" />
<input type="text" id="message" />
<input type="button" value="send" id="send" />
<div id='messages'></div>
<script type="text/javascript">
var socket,
$txt = document.getElementById('message'),
$user = document.getElementById('user'),
$messages = document.getElementById('messages');
if (typeof (WebSocket) !== 'undefined') {
socket = new WebSocket("ws://localhost/SimpleChatApplication/ChatHandler.ashx");
} else {
socket = new MozWebSocket("ws://localhost/SimpleChatApplication/ChatHandler.ashx");
}
socket.onmessage = function (msg) {
var $el = document.createElement('p');
$el.innerHTML = msg.data;
$messages.appendChild($el);
};
socket.onclose = function (event) {
alert('Мы потеряли её. Пожалуйста, обновите страницу');
};
document.getElementById('send').onclick = function () {
socket.send($user.value + ' : ' + $txt.value);
$txt.value = '';
};
</script>
</body>
</html>
Теперь мы можем запустить наш чат, но вот только свойство context.IsWebSocketRequest будет всегда false.
Это происходит из-за того, что Visual Studio по умолчанию для отладки использует IIS Express, который не поддерживает Web Socket. Для того, чтобы наконец поиграться с сокетами нам необходимо установить IIS и настроить Visual Studio для работы с ним по умолчанию.
Для этого выполним несколько шагов:
Шаг 1. Устанавливаем IIS.
Для этого перейдём в Панель управления -> Программы -> Включение и отключение компонентов Windows
Там найдём службы IIS и поставим на них галку
Шаг 2. Настраиваем IIS.
По умолчанию компонент Web Socket в IIS отключён. Чтобы его включить в компонентах Windows пройдём по пути Службы IIS -> Службы Интернета -> Компоненты разработки приложений. Там найдём Протокол WebSocket и поставим на нём галку
Шаг 3. Настраиваем Visual Studio.
Чтобы заставить VS использовать IIS для отладки, нам необходимо зайти в свойства проекта -> Веб и там отжать галку Использовать IIS Express. (Если галка у вас не активна, перезапустите студию)
Завершение
Теперь мы можем смело запустить наш проект и поприветствовать самого себя!
Скачать файл проекта можно здесь.
Автор: RoboNET
А ссылка не рабочая.