【问题标题】:ASP.NET Core 2.2 - SignalR How to join a group and send message from the server?ASP.NET Core 2.2 - SignalR 如何加入群组并从服务器发送消息?
【发布时间】:2019-12-24 02:05:13
【问题描述】:

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

所需的解决方案:

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

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

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

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

到目前为止我的代码:

MessageHub 类:

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

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 组的名称,用户可以从浏览器的下拉列表中选择该组,以便他们可以监视来自这个特定服务器实例的事件。其他用户可能希望监视来自不同服务器实例的事件。

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

【问题讨论】:

    标签: asp.net-core signalr


    【解决方案1】:

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

    枢纽:

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

    【讨论】:

    • 嗨,我不明白你的最后一个方法“connection.invoke...” 这里对我的关键要求是能够从服务器向组发送消息,而不是从另一个浏览器。似乎这条线:“等待_hubContext.Clients.Group(_serviceInstanceName).SendAsync("ReceiveMessage", message);"是什么可能会这样做,但是在测试了上述内容后它仍然对我不起作用。谢谢
    • 啊,我刚刚想通了,好的,我想我现在明白了,非常感谢您的帮助 :)
    • 当我向一个组发送消息时,它什么也不做,即使我注册了 await _hubContext.Groups.AddToGroupAsync(connectionId, Constants.Roles.Admin) ,然后用 await _hubContext 发送了一条消息.Clients.Groups("stringHere").SendAsync("Case", obj1, obj2);然后用发​​送
    猜你喜欢
    • 2018-12-25
    • 2018-11-20
    • 1970-01-01
    • 2021-11-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-29
    相关资源
    最近更新 更多