ASP.NET 核心 2.2 - 信号R 如何加入组并从服务器发送消息?



我为 SignalR 设置了一个基本解决方案,我可以通过浏览器向所有客户端发送和接收消息。

所需的解决方案:

我需要实现组的使用,但能够加入组并从服务器上运行的后台服务类发送消息。

目前,我只成功地从服务器向所有客户端发送了一条消息。

我的后台服务类(基本上是一个通信服务器(将运行多个实例,因此每个实例都有一个唯一的名称,例如通信服务器 1、通信服务器 2 等。通信服务器的每个实例都需要将消息输出到特定的 SignalR 收件人组。

在浏览器中,用户将从从服务器拉取的下拉列表中选择要加入的 SignalR 组。服务器也知道这个相同的列表,因此每个通信服务器实例将代表列表中的一个项目。

到目前为止我的代码:

消息中心类:

public class MessageHub : Hub
{
public Task SendMessageToAll(string message)
{
return Clients.All.SendAsync("ReceiveMessage", message);
}
}

消息.js文件:

"use strict";
var connection = new signalR.HubConnectionBuilder()
.withUrl("/messages")
.build();
connection.on("ReceiveMessage", function (message) {
var msg = message.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
var div = document.createElement("div");
div.innerHTML = msg + "<hr/>";
document.getElementById("messages").appendChild(div);
});
connection.start().catch(function (err) {
return console.error(err.toString());
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var message = document.getElementById("message").value;
connection.invoke("SendMessageToAll", message).catch(function (err) {
return console.error(err.toString());
});
e.preventDefault();
}); 

剃须刀页面:

<textarea name="message" id="message"></textarea>
<input type="button" id="sendButton" value="Send Message" />
<div id="messages"></div>
<script src="~/lib/signalr/dist/browser/signalr.js"></script>
<script src="~/js/message.js"></script> 

通信服务器类:

public class TcpServer
{
private readonly IHubContext<MessageHub> _hubContext;
public TcpServerTcpServer(IHubContext<MessageHub> hubContext)
{
_hubContext = hubContext;
}
public string inboundIpAddress = "127.0.0.1";
public int inboundLocalPortNumber = 10001;
public void TcpServerIN(string serverName)
{
Task.Run(() =>
{
IPAddress localAddrIN = IPAddress.Parse(inboundIpAddress);
TcpListener listener = new TcpListener(localAddrIN, inboundLocalPortNumber);
listener.Start();
while (true)
{
TcpClient client = listener.AcceptTcpClient();
// Get a stream object for reading and writing
NetworkStream stream = client.GetStream(); // Networkstream is used to send/receive messages
//Buffer for reading data
Byte[] bytes = new Byte[4096];
String data = null;
int i;
// Loop to receive all the data sent by the client.
while ((i = stream.Read(bytes, 0, bytes.Length)) != 0)
{
// Translate data bytes to a ASCII string.
data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
_hubContext.Clients.All.SendAsync(data);
byte[] msg = System.Text.Encoding.ASCII.GetBytes(data);
stream.Write(msg, 0, data.Length);
}
// Shutdown and end connection
client.Close();
}
});
}
}

我需要选择一个特定的 SignalR 组名称,例如"CommsServer 1",这将形成用户可以从浏览器的下拉列表中选择的 SignalR 组的名称,以便他们可以监视来自此特定服务器实例的事件。其他用户可能希望监视来自不同服务器实例的事件。

我正在考虑的一种选择是简单地将所有服务器实例中的事件发送到所有浏览器连接的客户端,然后以某种方式过滤客户端的事件,但这似乎是一种低效的处理方式,不利于网络流量。

如果您希望客户端决定加入哪个组(通过从下拉列表中选择(,那么客户端可能应该通过集线器通知服务器其订阅针对该组的消息:

枢纽:

public class MessageHub : Hub
{
public async Task SendMessageToAll(string message)
{
await Clients.All.SendAsync("ReceiveMessage", message);
}
public async Task Subscribe(string groupName)
{
await Groups.AddToGroupAsync(Context.ConnectionId, groupName);
}
}

后台服务:

public class TcpServer
{
private readonly IHubContext<MessageHub> _hubContext;
private readonly string _serviceInstanceName;
public TcpServerTcpServer(IHubContext<MessageHub> hubContext, string serviceInstanceName)
{
_hubContext = hubContext;
_serviceInstanceName = serviceInstanceName;
}
public async Task SendMessageToGroup(string message)
{
await _hubContext.Clients.Group(_serviceInstanceName).SendAsync("ReceiveMessage", message);
}
}

在客户端的某个地方,也许在用户从下拉列表中选择一个选项之后:

connection.invoke("subscribe", "CommsServer 1, or whatever").catch(function (err) {
return console.error(err.toString());
});

最新更新