Tôi đang làm việc trên một giải pháp sử dụng giao thức socket web để thông báo cho khách hàng (trình duyệt web) khi một số sự kiện xảy ra trên máy chủ (ứng dụng web MVC Core). Tôi sử dụng Microsoft.AspNetCore.WebSockets nuget.MVC Core, Web Sockets and threading
Đây là mã client-side của tôi:
$(function() {
var socket = new WebSocket("ws://localhost:61019/data/openSocket");
socket.onopen = function() {
$(".socket-status").css("color", "green");
}
socket.onmessage = function (message) {
$("body").append(document.createTextNode(message.data));
}
socket.onclose = function() {
$(".socket-status").css("color", "red");
}
});
Khi quan điểm này được nạp theo yêu cầu ổ cắm ngay lập tức được gửi đến các ứng dụng MVC Core. Đây là hành động của bộ điều khiển:
[Route("data")]
public class DataController : Controller
{
[Route("openSocket")]
[HttpGet]
public ActionResult OpenSocket()
{
if (HttpContext.WebSockets.IsWebSocketRequest)
{
WebSocket socket = HttpContext.WebSockets.AcceptWebSocketAsync().Result;
if (socket != null && socket.State == WebSocketState.Open)
{
while (!HttpContext.RequestAborted.IsCancellationRequested)
{
var response = string.Format("Hello! Time {0}", System.DateTime.Now.ToString());
var bytes = System.Text.Encoding.UTF8.GetBytes(response);
Task.Run(() => socket.SendAsync(new System.ArraySegment<byte>(bytes),
WebSocketMessageType.Text, true, CancellationToken.None));
Thread.Sleep(3000);
}
}
}
return new StatusCodeResult(101);
}
}
Mã này hoạt động rất tốt. WebSocket ở đây được sử dụng riêng cho việc gửi và không nhận bất cứ thứ gì. Tuy nhiên, vấn đề là vòng lặp while giữ nguyên chuỗi DataController cho đến khi yêu cầu hủy được phát hiện.
Ổ cắm web ở đây bị ràng buộc với đối tượng HttpContext. Ngay sau khi HttpContext cho yêu cầu web bị phá hủy, kết nối socket sẽ bị đóng ngay lập tức.
Câu hỏi 1: Có cách nào mà ổ cắm có thể được bảo quản bên ngoài luồng bộ điều khiển không? Tôi đã thử đưa nó vào một singleton sống trong lớp MVC Core Startup đang chạy trên chuỗi ứng dụng chính. Có cách nào để giữ cho các ổ cắm mở hoặc thiết lập kết nối một lần nữa từ bên trong thread ứng dụng chính chứ không phải giữ giữ thread điều khiển với một vòng lặp while? Thậm chí nếu nó được coi là OK để giữ thread điều khiển cho kết nối socket vẫn mở, tôi không thể nghĩ ra bất kỳ mã tốt nào để đặt bên trong vòng lặp while của OpenSocket. Bạn nghĩ gì về việc có một sự kiện đặt lại thủ công trong bộ điều khiển và đợi nó được đặt bên trong vòng lặp while trong hành động OpenSocket?
Câu hỏi 2: Nếu không thể tách các đối tượng HttpContext và WebSocket trong MVC, các công nghệ thay thế hoặc các mẫu phát triển khác có thể được sử dụng để đạt được tái sử dụng kết nối socket? Nếu bất cứ ai nghĩ rằng SignalR hoặc một thư viện tương tự có một số mã cho phép có ổ cắm độc lập từ HttpContext, hãy chia sẻ một số mã ví dụ. Nếu ai đó nghĩ rằng có một thay thế tốt hơn cho MVC cho kịch bản cụ thể này, xin vui lòng cung cấp một ví dụ, tôi không nhớ chuyển sang ASP.NET tinh khiết hoặc Web API, nếu MVC không có khả năng để xử lý truyền thông socket độc lập.
Câu hỏi 3: Yêu cầu là giữ kết nối ổ cắm còn sống hoặc có thể kết nối lại cho đến khi hết thời gian chờ hoặc yêu cầu hủy bỏ bởi người dùng. Ý tưởng là một số sự kiện độc lập xảy ra trên máy chủ kích hoạt ổ cắm được thiết lập để gửi dữ liệu. Nếu bạn nghĩ rằng một số công nghệ khác với ổ cắm web sẽ hữu ích hơn cho kịch bản này (như HTML/2 hoặc truyền trực tuyến), bạn có thể mô tả mô hình và khuôn khổ bạn sẽ sử dụng không?
P.S. Giải pháp có thể là gửi yêu cầu AJAX mỗi giây để hỏi xem có dữ liệu mới trên máy chủ hay không. Đây là phương sách cuối cùng.
'SignalR' trông rất hứa hẹn nhưng không thể cung cấp bất kỳ mã nào cho bạn vì không biết nhiều về nó. – VMAtm