2014-10-08 3 views
5

Я пытаюсь получить чат-сервис в режиме реального времени для кросс-платформенных устройств для жизни. Проблема в том, что пространство имен System.Net.WebSockets не позволяет мне отслеживать установленное соединение. Я мог бы взять sessionID текущего соединения, но как я могу сказать следующее действие await socket.SendAsync(buffer, WebSocketMessageType.Text, CancellationToken.None) для конкретного клиента?Как отслеживать установленные соединения с помощью WebSockets

Если бы я мог использовать 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

Что заставило вас выбрать WebSockets более SignalR ? Просто запустите, есть учебник для [сопоставления пользователей с соединениями] (http://www.asp.net/signalr/overview/guide-to-the-api/mapping-users-to-connections) с SignalR – Jonesopolis

+0

Я didn ' t знал, что SignalR поддерживается Android. WebSockets поддерживается изначально Windows и Xamarin, поэтому я хотел использовать это. Но, как я сейчас читаю, это было бы прекрасно! Спасибо, совет! – Flash1232

+0

SignalR - это просто абстракция по нескольким различным типам общения. Обычно он использует WebSockets. И это потрясающе, IMO – Jonesopolis

ответ

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(); 
    } 
} 
+0

Большое спасибо за этот уникальный код, который я не мог найти нигде! Я перешел на кодировку ASCII, потому что думал, что для UTF8 потребуется меньше ресурсов, чем кодирование. Я более подробно рассмотрю код, потому что SignalR не работает на продуктивных серверах, и альтернативы нет. Я также взгляну на MassTransit! – Flash1232

+0

Имейте в виду, что вам нужно Windows 2008/2012 запускать веб-сайты, даже если вы используете SignalR. Если у вас нет этих операционных систем, вы можете использовать инфраструктуру thirdparty, например my: http://vtortola.github.io/WebSocketListener/ – vtortola

+0

У меня установлена ​​установка Windows Server 2012 R2 с .NET Framework 4.5. Думаю, это должно сработать, но, как я уже сказал, это СЛЕДУЕТ ... но нет. – Flash1232

1

Я думаю, что изобретать колесо было бы очень глупо, поэтому я лучше использую SignalR для этой цели.

Благодарим @Jonesy за то, что сообщили мне об этой библиотеке Microsoft!

редактировать:

SignalR не работает должным образом на режиме без "IIS Express". «Local IIS» приводит к сбою всего проекта.

редактировать:

SignalR теперь работает. Правило перезаписи не позволило получить правильный путь.

+0

SignalR очень слаб с точки зрения масштабируемости, помните об этом. Они разъясняют их документацию. Проверьте часть «Масштабирование». – vtortola

+0

SignalR предназначен для небольших проектов или средних проектов, где вам необходимо транслировать несегментированную информацию. – vtortola

+0

Спасибо за информацию! У меня есть цель создать большую службу обмена сообщениями, поэтому она должна быть очень большой масштабируемой. – Flash1232

Смежные вопросы