6 major server modules (PdkFriendServer/GlobalSever/ServerCore/GameModule/GameNetModule) + game logic (GameFix/GameDAL/ServerData) + network layer (NetWorkMessage) + data layer (ObjectModel) + utilities (MrWu/Core/Config/CloudAPI/dll) + adapters (zyxAdapter/base) .NET 8.0 C# solution, 16 projects, 958 source files
249 lines
9.6 KiB
C#
249 lines
9.6 KiB
C#
/********************************
|
|
*
|
|
* 作者:吴隆健
|
|
* 创建时间: 2019/6/29 15:19:34
|
|
*
|
|
********************************/
|
|
|
|
using System;
|
|
using System.Collections.Concurrent;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using MrWu.Debug;
|
|
using RabbitMQ.Client;
|
|
using RabbitMQ.Client.Events;
|
|
|
|
namespace MrWu.RabbitMQ {
|
|
/// <summary>
|
|
/// RPC客户端
|
|
/// </summary>
|
|
public class RpcClient {
|
|
|
|
/// <summary>
|
|
/// 发送者
|
|
/// </summary>
|
|
private IModel channel;
|
|
|
|
private IConnection connection;
|
|
|
|
private readonly object lockObj = new object();
|
|
|
|
/// <summary>
|
|
/// rpc结果
|
|
/// </summary>
|
|
private readonly ConcurrentDictionary<string, string> respQueue = new ConcurrentDictionary<string, string>();
|
|
|
|
private RabbitConfig config;
|
|
|
|
private ushort prefetchCount;
|
|
|
|
/// <summary>
|
|
/// 消费者
|
|
/// </summary>
|
|
private EventingBasicConsumer consumer;
|
|
|
|
/// <summary>
|
|
/// 创建客户端
|
|
/// </summary>
|
|
/// <param name="config">rabbit配置</param>
|
|
/// <param name="prefetchCount">同时处理的数量</param>
|
|
internal RpcClient(RabbitConfig config, ushort prefetchCount) {
|
|
this.config = config;
|
|
this.prefetchCount = prefetchCount;
|
|
ConnectionFactory factory = new ConnectionFactory();
|
|
factory.UserName = config.username;
|
|
factory.Password = config.password;
|
|
factory.VirtualHost = config.vhost;
|
|
factory.HostName = config.host;
|
|
factory.Port = config.port;
|
|
factory.AutomaticRecoveryEnabled = true;
|
|
|
|
connection = factory.CreateConnection();
|
|
CreateChannel();
|
|
|
|
//this.CallBackTimeOutCheckTimer = new Timer(CallBackTimeoutCheck, null, 20, 20);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 关闭
|
|
/// </summary>
|
|
internal void Close() {
|
|
connection.Close();
|
|
}
|
|
|
|
private void CreateChannel() {
|
|
channel = connection.CreateModel();
|
|
var queue = channel.QueueDeclare();
|
|
reply_queue = queue.QueueName;
|
|
consumer = new EventingBasicConsumer(channel);
|
|
consumer.Received += Recive;
|
|
|
|
//Debug.Debug.Log("进来两次????");
|
|
//只会同时接收prefetchCount 个数据
|
|
channel.BasicQos(0, prefetchCount, false);
|
|
channel.BasicConsume(reply_queue, true, consumer);
|
|
}
|
|
|
|
/// <summary>
|
|
/// rpc 返回值队列
|
|
/// </summary>
|
|
private string reply_queue;
|
|
|
|
/// <summary>
|
|
/// 接收到消息
|
|
/// </summary>
|
|
/// <param name="model"></param>
|
|
/// <param name="msg"></param>
|
|
private void Recive(IBasicConsumer model, BasicDeliverEventArgs msg) {
|
|
//Console.WriteLine($"MrWU.RpcClient.Recive\t{DateTime.Now:hh:mm:ss.fffffff}\t{msg?.BasicProperties?.CorrelationId}");
|
|
//ThreadPool.QueueUserWorkItem(HandleRecvMsgThreadPoolMethod, msg);
|
|
Task.Factory.StartNew(
|
|
() => {
|
|
// Debug.Debug.Log("Rpc接收到消息:" + );
|
|
if (msg.BasicProperties == null)
|
|
return;
|
|
|
|
//Debug.Debug.Log("RPC 接收到消息:" + msg.BasicProperties.CorrelationId);
|
|
|
|
if (!respQueue.TryAdd(msg.BasicProperties.CorrelationId, Encoding.UTF8.GetString(msg.Body))) {
|
|
Debug.Debug.Error("RPC发送消息失败!" + msg.BasicProperties.CorrelationId);
|
|
}
|
|
}
|
|
);
|
|
|
|
/*
|
|
if (msg?.BasicProperties != null) {
|
|
var callbackResult = Encoding.UTF8.GetString(msg.Body);
|
|
//Debug.Debug.Log("RPC 接收到消息:" + msg.BasicProperties.CorrelationId);
|
|
if(AsyncTaskList.TryGetValue(msg.BasicProperties.CorrelationId, out var tuple)) {
|
|
tuple.Item3.TrySetResult(callbackResult);
|
|
} else if(!respQueue.TryAdd(msg.BasicProperties.CorrelationId, callbackResult)) {
|
|
Debug.Debug.Error("RPC发送消息失败!" + msg.BasicProperties.CorrelationId);
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 获取结果
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
private string GetReplyResult(string corrlationId, int waitTime = 3000) {
|
|
DateTime outtime = DateTime.Now.AddMilliseconds(waitTime);
|
|
//while (true) {
|
|
// //Debug.Debug.Log("处理处理接收消息:" + Thread.CurrentThread.ManagedThreadId);
|
|
// if (respQueue.ContainsKey(corrlationId)) {
|
|
// string msg = null;
|
|
// if (respQueue.TryGetValue(corrlationId, out msg)) {
|
|
// return msg;
|
|
// } else {
|
|
// Debug.Debug.Error("RPC消息竟被别人取走??");
|
|
// return null;
|
|
// }
|
|
// } else {
|
|
// Console.WriteLine($"MrWU.RpcClient.GetReplyResult for: {corrlationId},\t{}");
|
|
// }
|
|
// if (DateTime.Now > outtime)
|
|
// return null;
|
|
// Thread.Sleep(10);
|
|
//}
|
|
while(true) {
|
|
//Debug.Debug.Log("处理处理接收消息:" + Thread.CurrentThread.ManagedThreadId);
|
|
if(respQueue.TryRemove(corrlationId, out var msg)) {
|
|
return msg;
|
|
} else {
|
|
}
|
|
if(DateTime.Now > outtime)
|
|
return null;
|
|
Thread.Sleep(10);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// call 方法
|
|
/// </summary>
|
|
/// <param name="exchange">交换机</param>
|
|
/// <param name="routingkey">路由键</param>
|
|
/// <param name="message">消息</param>
|
|
/// <param name="waitTime">超时时间 毫秒值</param>
|
|
public string Call(string exchange, string routingkey, string message, int waitTime = 3000) {
|
|
// Debug.Debug.Log("call : " + reply_queue);
|
|
string correlationId = MessagePool.GetId();// Guid.NewGuid().ToString();
|
|
try {
|
|
lock(lockObj) {
|
|
if(channel == null || channel.IsClosed) {
|
|
CreateChannel();
|
|
}
|
|
}
|
|
IBasicProperties properties = channel.CreateBasicProperties();
|
|
properties.ReplyTo = reply_queue;
|
|
properties.CorrelationId = correlationId;
|
|
|
|
//Debug.Debug.Log("rpcCall :" + correlationId);
|
|
channel.BasicPublish(exchange, routingkey, properties, Encoding.UTF8.GetBytes(message));
|
|
var ret = GetReplyResult(correlationId, waitTime);
|
|
return ret;
|
|
|
|
} catch(Exception e) {
|
|
Debug.Debug.Error("Rpc出现错误!" + e.ToString());
|
|
return null;
|
|
}
|
|
}
|
|
|
|
//ConcurrentDictionary<string, Tuple<DateTime, string, TaskCompletionSource<string>>> AsyncTaskList { get; } = new ConcurrentDictionary<string, Tuple<DateTime, string, TaskCompletionSource<string>>>();
|
|
|
|
/*
|
|
/// <summary>
|
|
/// 异步Callback
|
|
/// </summary>
|
|
/// <param name="exchange"></param>
|
|
/// <param name="routingkey"></param>
|
|
/// <param name="message"></param>
|
|
/// <param name="waitTime"></param>
|
|
/// <returns></returns>
|
|
public Task<string> AsyncCall(string exchange, string routingkey, string message, int waitTime = 3000) {
|
|
var correlationId = Guid.NewGuid().ToString();
|
|
var taskSrc = new TaskCompletionSource<string>();
|
|
try {
|
|
lock(lockObj) {
|
|
if(channel == null || channel.IsClosed) {
|
|
CreateChannel();
|
|
}
|
|
}
|
|
var properties = channel.CreateBasicProperties();
|
|
properties.ReplyTo = reply_queue;
|
|
properties.CorrelationId = correlationId;
|
|
channel.BasicPublish(exchange, routingkey, properties, Encoding.UTF8.GetBytes(message));
|
|
AsyncTaskList.TryAdd(correlationId, new Tuple<DateTime, string, TaskCompletionSource<string>>(DateTime.Now.AddMilliseconds(waitTime), message, taskSrc));
|
|
} catch(Exception ex) {
|
|
Debug.Debug.Error("Rpc出现错误!" + ex.ToString());
|
|
taskSrc.TrySetException(new Exception("AsyncCall Rpc出现错误", ex));
|
|
}
|
|
return taskSrc.Task;
|
|
}
|
|
*/
|
|
|
|
/*
|
|
Timer CallBackTimeOutCheckTimer { get; }
|
|
|
|
|
|
void CallBackTimeoutCheck(object obj) {
|
|
var now = DateTime.Now;
|
|
var outdateItems = AsyncTaskList.Where(p => p.Value.Item1 < now).ToArray();
|
|
if(AsyncTaskList.Count>0 && outdateItems.Length == AsyncTaskList.Count) {
|
|
foreach(var item in outdateItems) {
|
|
if(AsyncTaskList.TryRemove(item.Key, out var tuple)) {
|
|
//tuple.Item3.TrySetException(new TimeoutException("超时检查: " + tuple.Item2));
|
|
tuple.Item3.TrySetResult(string.Empty);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
}
|
|
}
|