RabbitMQ .NET消息队列使用入门(三)【MVC实现RPC例子】

来源:互联网 发布:简益通讯淘宝店怎么样 编辑:程序博客网 时间:2024/05/05 00:02

每一个孤独的灵魂都需要陪伴

RPC(Remote Procedure Call Protocol)——远程过程调用协议,它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。RPC协议假定某些传输协议的存在,如TCP或UDP,为通信程序之间携带信息数据。在OSI网络通信模型中,RPC跨越了传输层和应用层。RPC使得开发包括网络分布式多程序在内的应用程序更加容易。

RPC采用客户机/服务器模式。请求程序就是一个客户机,而服务提供程序就是一个服务器。首先,客户机调用进程发送一个有进程参数的调用信息到服务进程,然后等待应答信息。在服务器端,进程保持睡眠状态直到调用信息到达为止。当一个调用信息到达,服务器获得进程参数,计算结果,发送答复信息,然后等待下一个调用信息,最后,客户端调用进程接收答复信息,获得进程结果,然后调用执行继续进行。

有多种 RPC模式和执行。最初由 Sun 公司提出。IETF ONC 宪章重新修订了 Sun 版本,使得 ONC RPC 协议成为 IETF 标准协议。现在使用最普遍的模式和执行是开放式软件基础的分布式计算环境(DCE)。

工作原理(以Windows下为例)

运行时,一次客户机对服务器的RPC调用,其内部操作大致有如下十步:
1.调用客户端句柄;执行传送参数
2.调用本地系统内核发送网络消息
3.消息传送到远程主机
4.服务器句柄得到消息并取得参数
5.执行远程过程
6.执行的过程将结果返回服务器句柄
7.服务器句柄返回结果,调用远程系统内核
8.消息传回本地主机
9.客户句柄由内核接收消息
10.客户接收句柄返回的数据

RPC OVER HTTP

Microsoft RPC-over-HTTP 部署(RPC over HTTP)允许RPC客户端安全和有效地通过Internet 连接到RPC 服务器程序并执行远程过程调用。这是在一个名称为RPC-over-HTTP 代理,或简称为RPC 代理的中间件的帮助下完成的。
RPC 代理运行在IIS计算机上。它接受来自Internet 的RPC 请求,在这些请求上执行认证,检验和访问检查,如果请求通过所有的测试,RPC 代理将请求转发给执行真正处理的RPC 服务器。通过RPC over HTTP,RPC客户端不和服务器直接通信,它们使用RPC 代理作为中间件。

新建一个控制台程序,Program.cs

using System;using System.Text;using System.Threading;using System.Threading.Tasks;using Common;using RabbitMQ.Client;using RabbitMQ.Client.Events;using RabbitMQ.Client.Exceptions;namespace RPCServer{     class Program    {        private static IConnection _recvConn; //接收消息的连接        private static IConnection _senderConn; //返回结果的连接        private static IModel _recvChannel; //接收消息的信道        private static IModel _sendChannel; //返回结果的信道        private static bool isExit;        private static void Main(string[] args)        {            Setup();            Console.WriteLine("开始使用RPC消息:");            WaitCommand();        }        private static void Setup()        {            var factory = new ConnectionFactory            {                HostName = "localhost",                UserName = "guest",                Password = "guest",                //VirtualHost = "test",                AutomaticRecoveryEnabled = true            };            try            {                _recvConn = factory.CreateConnection();                _recvChannel = _recvConn.CreateModel();                _recvChannel.QueueDeclare("rpcQueue", false, false, false, null);                _recvChannel.BasicQos(0, 10, false);                var consumer = new EventingBasicConsumer(_recvChannel);                consumer.Received += consumer_Received;                _recvChannel.BasicConsume("rpcQueue", false, consumer);                _senderConn = factory.CreateConnection();                //_sendChannel = _senderConn.CreateModel();            }            catch (BrokerUnreachableException ex)            {                Console.WriteLine("RabbitMQ服务器尚未启动!");                Thread.Sleep(2000);                isExit = true;            }        }        /// <summary>        ///     等待接收指令        /// </summary>        private static void WaitCommand()        {            while (!isExit)            {                string line = Console.ReadLine().ToLower().Trim();                switch (line)                {                    case "exit":                        Close();                        isExit = true;                        break;                    case "clear":                        Console.Clear();                        break;                    default:                        break;                }            }            Console.WriteLine("Goodbye!");        }        private static void Close()        {            if (_recvChannel != null && _recvChannel.IsOpen)            {                _recvChannel.Close();            }            if (_recvConn != null && _recvConn.IsOpen)            {                _recvConn.Close();            }            if (_senderConn != null && _senderConn.IsOpen)            {                _senderConn.Close();            }        }        private static void consumer_Received(object sender, BasicDeliverEventArgs e)        {            byte[] body = e.Body;            Task.Run(() => HandlingMessage(body, e));        }        /// <summary>        ///     消息处理        /// </summary>        /// <param name="msgModel"></param>        /// <param name="e"></param>        private static async void HandlingMessage(byte[] body, BasicDeliverEventArgs e)        {            bool isSuccess = false;            bool hasRejected = false;            string message = Encoding.UTF8.GetString(body);            string replyMsg = "";            IModel _senderChannel = null;            try            {                _senderChannel = _senderConn.CreateModel(); //多线程中每个线程使用独立的信道                replyMsg = message + "   处理成功";                var random = new Random();                int num = random.Next(0, 4);                //模拟处理失败                /*if (random.Next(0, 11) == 4)                {                    throw new Exception("处理失败", null);                }*/                //模拟解析失败                if (random.Next(0, 11) == 8)                {                    throw new MessageException("消息解析失败");                }                //await Task.Delay(num * 1000);   //模拟消息处理                //这里简单处理,仅格式化输出消息内容                Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId +                                  " Used: " + num + "s MSG:" + message);                isSuccess = true;            }            catch (MessageException msgEx)            {                Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId +                                  " ERROR:" + msgEx.Message + " MSG:" + message);                _recvChannel.BasicReject(e.DeliveryTag, false); //不再重新分发                hasRejected = true;                replyMsg = message + "解析失败";                isSuccess = true;            }            catch (Exception ex)            {                Console.WriteLine("Time:" + DateTime.Now + " ThreadID:" + Thread.CurrentThread.ManagedThreadId +                                  " ERROR:" + ex.Message + " MSG:" + message);                replyMsg = "处理失败";            }            if (isSuccess)            {                try                {                    IBasicProperties props = e.BasicProperties;                    IBasicProperties replyProps = _senderChannel.CreateBasicProperties();                    replyProps.CorrelationId = props.CorrelationId;                    _senderChannel.BasicPublish("", e.BasicProperties.ReplyTo, replyProps, Encoding.UTF8.GetBytes(replyMsg)); //发送消息到内容检查队列                    if (!hasRejected)                    {                        _recvChannel.BasicAck(e.DeliveryTag, false); //确认处理成功  此处与不再重新分发,只能出现一次                    }                }                catch (AlreadyClosedException acEx)                {                    Console.WriteLine("ERROR:连接已关闭");                }            }            else            {                _recvChannel.BasicReject(e.DeliveryTag, true); //处理失败,重新分发            }            _senderChannel.Close();        }    }}

MVC站点

TestViewModel.cs代码:

 public class TestViewModel {        public string ReplyMessage { get; set; } }

TestController.cs代码:

using System;using System.Collections.Generic;using System.Linq;using System.Web;using System.Web.Mvc;using System.Text;using RabbitMQ.Client;using RabbitMQ.Client.Exceptions;using Common;using WebApp.Models;using System.Threading.Tasks;namespace WebApp.Controllers{    public class TestController : AsyncController    {         // GET: /Test/        public async Task<ActionResult> Index()        {                 TestViewModel viewModel = new TestViewModel() { ReplyMessage = "交换机关闭着." };                 return View(viewModel);         }        [HttpPost]        public async Task<MvcHtmlString> DoWork()        {            string message = "消息:" + new Random().Next(1, 10000).ToString();            string replyMsg = "";            RPCClient client = null;            try            {                 client = RPCClient.GetInstance();                replyMsg = await client.CallAsync(message);            }            catch (AlreadyClosedException e)            {                replyMsg = "交换机关闭着.";            }            catch (NoRPCConsumeException ex)            {                replyMsg = ex.Message;            }            catch (Exception e)            {                replyMsg = e.Message;            }             return new MvcHtmlString("<p>" + replyMsg + "</p>");        }        public async Task<ActionResult> Serv()        {            string message = "消息:" + new Random().Next(1, 10000).ToString();            var client = new ServiceReference1.WebService1SoapClient();            string reply = (await client.HandlerMessageAsync(message)).Body.HandlerMessageResult;            TestViewModel viewModel = new TestViewModel() { ReplyMessage = reply };            return View("Index", viewModel);        }     }}

Index.cshtml

@model WebApp.Models.TestViewModel@{    Layout = null;}<!DOCTYPE html><html><head>    <meta name="viewport" content="width=device-width" />    <title>Index</title></head><body>    <input type="button" name="sendBtn" id="sendBtn" value="发一条消息到队列" />    <div id="receiveArea">         <p>@Model.ReplyMessage</p>    </div>    <script src="~/Scripts/jquery-1.10.2.min.js"></script>    <script>        $("#sendBtn").on("click", function () {            $.ajax({                url: "/Test/DoWork",                dataType: "html",                type: "POST",                success: function (result) {                    console.log(result);                    $("#receiveArea").append($(result));                }            });        });    </script></body></html>

运行结果如图:

这里写图片描述

这里写图片描述

0 0
原创粉丝点击