Как работать с System.Net.WebSockets без ASP.NET?

Я хочу реализовать простой чат-сервер с новыми классами System.Net.WebSockets в .NET 4.5 и более поздних версиях (в Windows 8.1). Тем не менее, я нахожу только примеры, использующие эти классы в среде ASP.NET(особенно здесь: http://www.codemag.com/Article/1210051)

У меня его нет, и я хотел бы использовать сервер websocket как "необработанный", но без необходимости переопределять весь протокол websocket, поскольку Microsoft, надеюсь, уже делал это в .NET 4.5.

Я думал просто создать экземпляр нового класса WebSocket, как я бы сделал с обычным Socket, но конструктор защищен. Поэтому я пошел создавать класс, наследующий от него, но затем я заметил, что мне пришлось реализовать так много абстрактных методов и свойств, что это похоже на то, что я переписываю всю логику (особенно потому, что мне пришлось реализовать такие вещи, как State или SendAsync).

Я боюсь, что документация MSDN мне не помогла. Документация там имеет статус предварительного выпуска, и многие комментарии просто говорят "TBD" или "когда она реализована".

Ответ 1

Я просто наткнулся на эту ссылку, которая показывает, как реализовать IHttpHandler, используя только реализацию System.Net.WebSockets. Обработчик необходим, так как реализация .NET WebSocket зависит от IIS 8 +.

using System;
using System.Web;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.WebSockets;

namespace AspNetWebSocketEcho
{
    public class EchoHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            if (context.IsWebSocketRequest)
                context.AcceptWebSocketRequest(HandleWebSocket);
            else
                context.Response.StatusCode = 400;
        }

        private async Task HandleWebSocket(WebSocketContext wsContext)
        {
            const int maxMessageSize = 1024;
            byte[] receiveBuffer = new byte[maxMessageSize];
            WebSocket socket = wsContext.WebSocket;

            while (socket.State == WebSocketState.Open)
            {
                WebSocketReceiveResult receiveResult = await socket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer), CancellationToken.None);

                if (receiveResult.MessageType == WebSocketMessageType.Close)
                {
                    await socket.CloseAsync(WebSocketCloseStatus.NormalClosure, string.Empty, CancellationToken.None);
                }
                else if (receiveResult.MessageType == WebSocketMessageType.Binary)
                {
                    await socket.CloseAsync(WebSocketCloseStatus.InvalidMessageType, "Cannot accept binary frame", CancellationToken.None);
                }
                else
                {
                    int count = receiveResult.Count;

                    while (receiveResult.EndOfMessage == false)
                    {
                        if (count >= maxMessageSize)
                        {
                            string closeMessage = string.Format("Maximum message size: {0} bytes.", maxMessageSize);
                            await socket.CloseAsync(WebSocketCloseStatus.MessageTooLarge, closeMessage, CancellationToken.None);
                            return;
                        }

                        receiveResult = await socket.ReceiveAsync(new ArraySegment<byte>(receiveBuffer, count, maxMessageSize - count), CancellationToken.None);
                        count += receiveResult.Count;
                    }

                    var receivedString = Encoding.UTF8.GetString(receiveBuffer, 0, count);
                    var echoString = "You said " + receivedString;
                    ArraySegment<byte> outputBuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(echoString));

                    await socket.SendAsync(outputBuffer, WebSocketMessageType.Text, true, CancellationToken.None);
                }
            }
        }

        public bool IsReusable
        {
            get { return true; }
        }
    }
}

Надеюсь, что это помогло!

Ответ 2

Да.

Самый простой способ - использовать HTTPListener. Если вы ищете HTTPListener WebSocket, вы найдете множество примеров.

В двух словах (псевдокод)

HTTPListener httpListener = new HttpListener();
httpListener.Prefixes.Add("http://localhost/");
httpListener.Start();

HTTPListenerContext context = await httpListener.GetContextAsync();
if (context.Request.IsWebSocketRequest)
{
    HTTPListenerWebSocketContext webSocketContext = await context.AcceptWebSocketAsync(null);
    WebSocket webSocket = webSocketContext.WebSocket;
    while (webSocket.State == WebSocketState.Open)
    {
        await webSocket.SendAsync( ... );
    }
}

Требуется .NET 4.5 и Windows 8 или новее.