如何使用WebSockets跟踪已建立的连接

时间:2014-10-08 17:53:51

标签: c# asp.net session websocket connection

我正在努力为跨平台设备提供实时聊天服务。问题是 System.Net.WebSockets命名空间不允许我直接跟踪已建立的连接。我可以获取当前连接的sessionID但是如何为特定客户端执行以下操作await socket.SendAsync(buffer, WebSocketMessageType.Text, CancellationToken.None)

如果我可以使用Microsoft.WebSockets,我可以创建WebSocketCollection()并执行client.Send(message)之类的操作,但我无法发送ArraySegment<byte[]>通过它。我也认为这更适用于AJAX客户端和网站以及这些东西。

我现在有以下代码段:

public class WSHandler : IHttpHandler
{
    event NewConnectionEventHandler NewConnection;
    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
        {
            context.AcceptWebSocketRequest(ProcessWSChat);
        }
    }

    public bool IsReusable { get { return false; } }
    private async Task ProcessWSChat(AspNetWebSocketContext context)
    {
        WebSocket socket = context.WebSocket;
        int myHash = socket.GetHashCode();
        while (true)
        {
        ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[1024]);
        WebSocketReceiveResult result = await socket.ReceiveAsync(
            buffer, CancellationToken.None);
            if (socket.State == WebSocketState.Open)
            {
                string userMessage = Encoding.ASCII.GetString(
                    buffer.Array, 0, result.Count);
                userMessage = "You sent: " + userMessage + " at " +
                    DateTime.Now.ToLongTimeString() + " from ip " +
                    context.UserHostAddress.ToString();
                buffer = new ArraySegment<byte>(
                    Encoding.ASCII.GetBytes(userMessage));
                await socket.SendAsync(
                    buffer, WebSocketMessageType.Text, true, CancellationToken.None);
            }
            else
            {
                break;
            }
        }
    }
}

如何扩展我的项目,保存会话/连接并调用特定的用户连接以便向其发送消息?

2 个答案:

答案 0 :(得分:2)

通常,你不会做那样的事情。 WebSocket应该只是另一个层或子系统的端点。例如,事件驱动的体系结构。在连接时,您应该启动处理程序,从连接的套接字收集数据,如cookie,URL或其他任何内容,并通知其他具有该cookie / url的用户在该套接字中连接的其他内容。

关于您的代码:

  • 不要在循环中声明读取缓冲区,您可以重复使用它。
  • WebSockets始终将文本数据发送为UTF8,而不是ASCII。

这是一种在小项目中跟踪用户的方法,但我建议您将WebSocket插入另一个消息基础架构,如MassTransit:

public class WSHandler : IHttpHandler
{
    public bool IsReusable { get { return false; } }

    public void ProcessRequest(HttpContext context)
    {
        if (context.IsWebSocketRequest)
        {
            context.AcceptWebSocketRequest(ProcessWSChat);
        }
    }

    static readonly ConcurrentDictionary<IPrincipal, WebSocket> _users = new ConcurrentDictionary<IPrincipal, WebSocket>();

    private async Task ProcessWSChat(AspNetWebSocketContext context)
    {
        WebSocket socket = context.WebSocket;
        ArraySegment<byte> buffer = new ArraySegment<byte>(new byte[4096]);

        //Identify user by cookie or whatever and create a user Object
        var cookie = context.Cookies["mycookie"];
        var url = context.RequestUri;

        IPrincipal myUser = GetUser(cookie, url);

        // Or uses the user that came from the ASP.NET authentication.
        myUser = context.User;

        _users.AddOrUpdate(myUser, socket, (p, w) => socket);

        while (socket.State == WebSocketState.Open)
        {
            WebSocketReceiveResult result = await socket.ReceiveAsync(buffer, CancellationToken.None)
                                                        .ConfigureAwait(false);
            String userMessage = Encoding.UTF8.GetString(buffer.Array, 0, result.Count);

            userMessage = "You sent: " + userMessage + " at " +
                DateTime.Now.ToLongTimeString() + " from ip " + context.UserHostAddress.ToString();
            var sendbuffer = new ArraySegment<byte>(Encoding.UTF8.GetBytes(userMessage));

            await socket.SendAsync(sendbuffer , WebSocketMessageType.Text, true, CancellationToken.None)
                        .ConfigureAwait(false);
        }

        // when the connection ends, try to remove the user
        WebSocket ows;
        if (_users.TryRemove(myUser, out ows))
        {
            if (ows != socket)
            {
                // whops! user reconnected too fast and you are removing
                // the new connection, put it back
                _users.AddOrUpdate(myUser, ows, (p, w) => ows);
            }
        }
    }

    private IPrincipal GetUser(HttpCookie cookie, Uri url)
    {
        throw new NotImplementedException();
    }
}

答案 1 :(得分:1)

我想重新发明轮子会非常愚蠢,所以我最好将SignalR用于此目的。

感谢@Jonesy让我了解这个Microsoft库!

修改

SignalR在非“IIS Express”模式下无法正常工作。 “本地IIS”导致整个项目失败。

修改

SignalR现在正常工作。重写规则使得无法获得正确的路径。