206 lines
4.9 KiB
C#
206 lines
4.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Net.WebSockets;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using System.Web;
|
|
using System.Web.WebSockets;
|
|
|
|
namespace Web12306
|
|
{
|
|
public class ChatServers : IHttpHandler
|
|
{
|
|
static ChatServers()
|
|
{
|
|
ThreadPool.QueueUserWorkItem(_ => SendMessageQueue());
|
|
}
|
|
|
|
/// <summary>
|
|
/// 您将需要在网站的 Web.config 文件中配置此处理程序
|
|
/// 并向 IIS 注册它,然后才能使用它。有关详细信息,
|
|
/// 请参见下面的链接: http://go.microsoft.com/?linkid=8101007
|
|
/// </summary>
|
|
#region IHttpHandler Members
|
|
|
|
public bool IsReusable
|
|
{
|
|
// 如果无法为其他请求重用托管处理程序,则返回 false。
|
|
// 如果按请求保留某些状态信息,则通常这将为 false。
|
|
get { return false; }
|
|
}
|
|
|
|
public void ProcessRequest(HttpContext context)
|
|
{
|
|
|
|
if (context.IsWebSocketRequest)
|
|
{
|
|
//if(context.WebSocketNegotiatedProtocol=="Fish12306")
|
|
context.AcceptWebSocketRequest(ProcessChat);
|
|
}
|
|
else
|
|
{
|
|
context.Response.ContentType = "application/json";
|
|
context.Response.WriteFile(context.Server.MapPath("/chatservers.json"));
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
static readonly List<AspNetWebSocketContext> _allContexts = new List<AspNetWebSocketContext>();
|
|
static readonly Dictionary<string, List<AspNetWebSocketContext>> _allRooms = new Dictionary<string, List<AspNetWebSocketContext>>();
|
|
static readonly Dictionary<string, AspNetWebSocketContext[]> _allRoomsCache = new Dictionary<string, AspNetWebSocketContext[]>();
|
|
static readonly Dictionary<string, Queue<ArraySegment<byte>>> _roomsSendingQueue = new Dictionary<string, Queue<ArraySegment<byte>>>();
|
|
|
|
static AutoResetEvent _eventSingal = new AutoResetEvent(true);
|
|
|
|
static void SendMessageQueue()
|
|
{
|
|
while (true)
|
|
{
|
|
_eventSingal.WaitOne();
|
|
|
|
var allQueues = _roomsSendingQueue.ToArray();
|
|
foreach (var queueData in allQueues)
|
|
{
|
|
var roomid = queueData.Key;
|
|
var queue = queueData.Value;
|
|
|
|
AspNetWebSocketContext[] contexts;
|
|
lock (_allRoomsCache)
|
|
{
|
|
if (!_allRoomsCache.TryGetValue(roomid, out contexts))
|
|
{
|
|
List<AspNetWebSocketContext> contextList;
|
|
lock (_allRooms)
|
|
{
|
|
if (!_allRooms.TryGetValue(roomid, out contextList) || contextList == null)
|
|
continue;
|
|
}
|
|
lock (contextList)
|
|
{
|
|
contexts = contextList.ToArray();
|
|
_allRoomsCache.Add(roomid, contexts);
|
|
}
|
|
}
|
|
}
|
|
if (queue.Count > 0)
|
|
{
|
|
ArraySegment<byte>[] dataItems = null;
|
|
lock (queue)
|
|
{
|
|
dataItems = queue.ToArray();
|
|
queue.Clear();
|
|
}
|
|
if (dataItems.Length == 0)
|
|
continue;
|
|
|
|
foreach (var context in contexts)
|
|
{
|
|
if (!context.IsClientConnected || context.WebSocket.State != WebSocketState.Open)
|
|
continue;
|
|
|
|
try
|
|
{
|
|
for (int i = 0; i < dataItems.Length; i++)
|
|
{
|
|
context.WebSocket.SendAsync(dataItems[i], WebSocketMessageType.Text, i == dataItems.Length - 1, CancellationToken.None);
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
|
|
}
|
|
finally
|
|
{
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task ProcessChat(AspNetWebSocketContext context)
|
|
{
|
|
WebSocket socket = context.WebSocket;
|
|
var path = context.Path.Trim('/');
|
|
var roomid = path.Substring(path.LastIndexOf('/') + 1);
|
|
List<AspNetWebSocketContext> room;
|
|
|
|
lock (_allContexts)
|
|
{
|
|
_allContexts.Add(context);
|
|
|
|
if (!_allRooms.TryGetValue(roomid, out room))
|
|
{
|
|
|
|
room = new List<AspNetWebSocketContext>();
|
|
_allRooms.Add(roomid, room);
|
|
}
|
|
room.Add(context);
|
|
}
|
|
lock (_allRoomsCache)
|
|
{
|
|
if (_allRoomsCache.ContainsKey(roomid))
|
|
_allRoomsCache.Remove(roomid);
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
if (socket.State == WebSocketState.Open)
|
|
{
|
|
var buffer = new ArraySegment<byte>(new byte[2048]);
|
|
var result = await socket.ReceiveAsync(buffer, CancellationToken.None);
|
|
|
|
if (result.Count > 0)
|
|
{
|
|
//房间
|
|
lock (_roomsSendingQueue)
|
|
{
|
|
Queue<ArraySegment<byte>> queue;
|
|
if (!_roomsSendingQueue.TryGetValue(roomid, out queue))
|
|
{
|
|
queue = new Queue<ArraySegment<byte>>(0x400);
|
|
_roomsSendingQueue.Add(roomid, queue);
|
|
}
|
|
lock (queue)
|
|
{
|
|
queue.Enqueue(new ArraySegment<byte>(buffer.Array, 0, result.Count));
|
|
}
|
|
_eventSingal.Set();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
lock (_allContexts)
|
|
{
|
|
_allContexts.Remove(context);
|
|
|
|
}
|
|
lock (_allRooms)
|
|
{
|
|
List<AspNetWebSocketContext> roomlist;
|
|
if (_allRooms.TryGetValue(roomid, out roomlist))
|
|
{
|
|
lock (roomlist)
|
|
{
|
|
roomlist.Remove(context);
|
|
}
|
|
}
|
|
|
|
}
|
|
lock (_allRoomsCache)
|
|
{
|
|
if (_allRoomsCache.ContainsKey(roomid))
|
|
_allRoomsCache.Remove(roomid);
|
|
}
|
|
}
|
|
}
|
|
}
|