使用WCF实现消息推送
1.协议
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel; namespace WCFHub.IService
{
[ServiceContract(CallbackContract=typeof(IEventCallback))]
public interface IEventService
{
[OperationContract(IsOneWay = true)]
void Subscribe(SubscribeArg a); [OperationContract(IsOneWay = true)]
void Unsubscribe(ArgumentBase<String> a); [OperationContract]
DateTime Ping(); } public interface IEventCallback
{
[OperationContract(IsOneWay = true)]
void OnMessageReceived(ArgumentBase<String> a);
}
}
2.实现
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Concurrent;
using System.ServiceModel;
using System.ServiceModel.Channels; namespace WCFHub.IService
{
public class EventServiceImpl:IEventService
{
public static readonly ConcurrentDictionary<String, SubscribeContext> _Subscribers = new ConcurrentDictionary<String, SubscribeContext>(); public string ClientIpAndPort()
{
OperationContext context = OperationContext.Current;
MessageProperties properties = context.IncomingMessageProperties;
RemoteEndpointMessageProperty endpoint = properties[RemoteEndpointMessageProperty.Name] as RemoteEndpointMessageProperty;
return endpoint.Address + ":" + endpoint.Port.ToString();
} public void Subscribe(SubscribeArg a)
{
Console.WriteLine(ClientIpAndPort()); var callback = OperationContext.Current.GetCallbackChannel<IEventCallback>();
a.Username=a.Username.ToLower();
_Subscribers[a.Username]=new SubscribeContext(){Arg=a,Callback=callback}; #region 事件处理
ICommunicationObject obj = (ICommunicationObject)callback;
obj.Closed += (s,e) =>
{ Console.WriteLine("Closed");
}; obj.Faulted += (s, e) => { Console.WriteLine("Faulted");
}; obj.Closing += (s,e) =>
{ Console.WriteLine("Closeing" + OperationContext.Current); var callback2=(IEventCallback)s; _Subscribers.ToList().ForEach(ent => { if (ent.Value.Callback == callback2)
{
RemoveSubscriber(ent.Value.Arg.Username);
}
});
};
#endregion } public void Unsubscribe(ArgumentBase<string> a)
{
RemoveSubscriber(a.Model); }
private static void RemoveSubscriber(string username)
{
username = username.ToLower();
if (_Subscribers.ContainsKey(username))
{
SubscribeContext outObj = null;
_Subscribers.TryRemove(username, out outObj);
}
} public static void PostData(ArgumentBase<string> a)
{
Console.WriteLine("收到待发消息:" + a.Model); _Subscribers.ToList().ForEach(subscriber =>
{ ICommunicationObject callback = (ICommunicationObject)subscriber.Value.Callback;
if (((ICommunicationObject)callback).State == CommunicationState.Opened)
{
try
{
//此处需要加上权限判断、订阅判断等
subscriber.Value.Callback.OnMessageReceived(a);
}
catch (Exception ex)
{
RemoveSubscriber(subscriber.Value.Arg.Username);
Console.WriteLine("PostData:" + ex.Message);
}
}
else
{
RemoveSubscriber(subscriber.Value.Arg.Username);
Console.WriteLine("PostData,用户链接已经关闭");
} });
} #region IEventService 成员 public DateTime Ping()
{
Console.WriteLine("Ping:" + ClientIpAndPort() +"," +DateTime.Now);
return DateTime.Now;
} #endregion
} public class SubscribeContext
{
public SubscribeArg Arg { get; set; }
public IEventCallback Callback { get; set; } }
}
3.实体类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; namespace WCFHub.IService
{
[Serializable]
public class ArgumentBase<T>
{
private int code;
private string msg;
private T model; public int Code
{
get { return code; }
set { code = value; }
}
public string Msg
{
get { return msg; }
set { msg = value; }
}
public T Model
{
get { return model; }
set { model = value; } }
} public class SubscribeArg : ArgumentBase<int>
{
public String Username { get; set; }
public List<int> Alarms { get; set; }
public SubscribeArg()
{
Alarms = new List<int>();
}
}
}
4.服务托管
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using WCFHub.IService; namespace WCFHub.Win
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private ServiceHost _Host = new ServiceHost(typeof(EventServiceImpl)); private void Form1_Load(object sender, EventArgs e)
{
_Host.AddServiceEndpoint(typeof(IEventService), new NetTcpBinding(SecurityMode.None),
"net.tcp://192.168.30.30:9999/EventService"
);
_Host.Open();
Console.WriteLine("服务开启...");
}
protected override void OnClosed(EventArgs e)
{
_Host.Close();
base.OnClosed(e);
Console.WriteLine("服务关闭!");
} private void button1_Click(object sender, EventArgs e)
{
var data = new ArgumentBase<string>() { Model = textBox1.Text + "," + DateTime.Now.ToString() };
EventServiceImpl.PostData(data);
}
}
}
5.客户端
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using WCFHub.IService;
using System.ServiceModel;
using System.Threading; namespace WCFHub.WinClient
{
#region MessageReceive
public delegate void MessageReceivedHandle(ArgumentBase<string> a); public class NotifyManager : IEventCallback
{ public event MessageReceivedHandle MessageReceived; public static int C_MaxErrCount = ;
public static int C_HeartbeatInterval = * ;//10秒一次心跳检测
IEventService _Proxy = null;
private int ErrCounter = ; public bool Enabled { get; set; } public NotifyManager()
{
Enabled = false;
} private void Close()
{
if (_Proxy != null)
{
try
{
var comObj = _Proxy as ICommunicationObject;
comObj.Abort();
}
catch { }
}
}
public void Start()
{
Enabled = true;
StartInternal();
#region 心跳检测
var timer = new System.Timers.Timer();
timer.Enabled = false;
timer.Interval = C_HeartbeatInterval;
timer.Elapsed += (s, ie) =>
{
try
{
WriteLine("心跳检测...");
timer.Enabled = false;
_Proxy.Ping();
ErrCounter = ;
}
catch (Exception ex)
{
WriteLine(ex.Message); ErrCounter++;
if (ErrCounter >= C_MaxErrCount)
{
Close();
StartInternal();
}
}
finally
{
timer.Enabled = true;
}
};
timer.Start();
#endregion
} private void StartInternal()
{
if (!Enabled) return; lock (this)
{ try
{
#region
ErrCounter = ; _Proxy = WCFHelper.Factory.CreateChannel(new InstanceContext(this)); var comObj = _Proxy as ICommunicationObject; comObj.Faulted += (s, ie) =>
{
WriteLine("Faulted"); };
comObj.Closed += (s, ie) =>
{
WriteLine("Closed!");
};
comObj.Closing += (s, ie) =>
{
WriteLine("Closing!");
}; WriteLine("加载并配置完成!"); _Proxy.Subscribe(new SubscribeArg() { Username = Guid.NewGuid().ToString("N") });
WriteLine("注册成功!");
#endregion }
catch (Exception ex)
{ WriteLine(ex.Message); }
}
} public void Stop()
{
Enabled = false;
Close();
} public void WriteLine(string msg)
{
Console.WriteLine(msg + "," + DateTime.Now);
} #region IEventCallback 成员 public void OnMessageReceived(ArgumentBase<string> a)
{
if (MessageReceived != null)
{
MessageReceived(a);
}
} #endregion
}
#endregion public partial class Form1 : Form
{
private SynchronizationContext SyncContext = null;
public Form1()
{
InitializeComponent();
SyncContext = SynchronizationContext.Current;
} NotifyManager _NotifyManager = null; private void Form1_Load(object sender, EventArgs e)
{ _NotifyManager = new NotifyManager();
_NotifyManager.MessageReceived += OnMessageReceived;
_NotifyManager.Start();
}
protected override void OnClosed(EventArgs e)
{
if (_NotifyManager != null)
{
_NotifyManager.MessageReceived -= this.OnMessageReceived;
_NotifyManager.Stop();
}
base.OnClosed(e);
} public void OnMessageReceived(ArgumentBase<string> a)
{
Console.WriteLine("收到消息:" + a.Model +",InvokeRequired:" + this.InvokeRequired); if (this.InvokeRequired)
{
SyncContext.Post((d) =>
{
textBox1.Text += a.Model + Environment.NewLine;
}, null);
}
else
{
textBox1.Text += a.Model + Environment.NewLine;
}
} private void button1_Click(object sender, EventArgs e)
{
if (_NotifyManager != null)
{
Console.WriteLine((_NotifyManager as ICommunicationObject).State);
}
}
} public class WCFHelper
{ private static DuplexChannelFactory<IEventService> _channelFac; public static DuplexChannelFactory<IEventService> Factory
{
get
{
if (_channelFac == null)
{
_channelFac =
new DuplexChannelFactory<IEventService>(typeof(NotifyManager), new NetTcpBinding(SecurityMode.None),
EndpointStr); }
return _channelFac;
}
} private static string EndpointStr
{
get
{
return "net.tcp://192.168.30.30:9999/EventService";
}
}
}
}
使用WCF实现消息推送的更多相关文章
- SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)
SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=>提升,5个Demo贯彻全篇,感兴趣的玩才是真的学) 官方demo:http://www.asp.net/si ...
- 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送
微信支付之微信模板消息推送 今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...
- 基于SignalR的消息推送与二维码描登录实现
1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...
- C# BS消息推送 SignalR介绍(一)
1. 前言 本文是根据网上前人的总结得出的. 环境: SignalR2.x,VS2015,Win10 介绍 1)SignalR能用来持久客户端与服务端的连接,让我们便于开发一些实时的应用,例如聊天室在 ...
- iOS 之消息推送(个推)---个人小结
前言:自从上个星期开始整这个推送,弄了差不多一个星期,今天终于给整好了,因此现在来记录这段"奇妙"的旅程. 我们公司使用的消息推送是用的第三方--个推,这里不得不说一下,个推的技术 ...
- WebSocket与消息推送
B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链 ...
- 分分钟搞定IOS远程消息推送
一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...
- 基于ajax与msmq技术的消息推送功能实现
周末在家捣鼓了一下消息推送的简单例子,其实也没什么技术含量,欢迎大伙拍砖.我设计的这个推送demo是基于ajax长轮询+msmq消息队列来实现的,具体交互过程如下图: 先说说这个ajax长轮询,多长时 ...
- C# BS消息推送 SignalR Hubs环境搭建与开发(二)
1. 前言 本文是根据网上前人的总结得出的. 环境: SignalR2.x,VS2015,Win10 2. 开始开发 1)新建一个MVC项目,叫做SignalRDemo 2)安装SignalR包 In ...
随机推荐
- 【Xamarin】Visual Studio 2013 Xamarin for iOS 环境搭建
一.Mac安装Xamarin.iOS 1,我的Mac 环境:OSX 10.10.3.Xcode 6.3.2 (使用虚拟机亲测也成功 VMware 11 安装 Mac OS X10.10 ) Xam ...
- 全面剖析Smarty缓存机制一[三种缓存方式]
今天主要全面总结下Smarty模板引擎中强大的缓存机制,缓存机制有效减少了系统对服务器的压力,而这也是很多开发者喜欢Smarty的原因之一,由于篇幅较大,便于博友阅读,这篇文章将剖析Smarty缓存的 ...
- FastAdmin 插件配置文件 info.ini 中的 state 什么意思?
FastAdmin 插件配置文件 info.ini 中的 state 什么意思? 在插件配置中有一个 state ,这是配置插件开关的.
- SQL Server中的事务与其隔离级别之脏读, 未提交读,不可重复读和幻读
原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...
- 在Linux中安装Oracle(较详细图解)
原创 http://www.cnblogs.com/nucdy/p/5603998.html 参考视屏:链接: https://pan.baidu.com/s/1kViEZQZ 密码: z7ha ( ...
- Python调用R语言
网络上经常看到有人问数据分析是学习Python好还是R语言好,还有一些争论Python好还是R好的文章.每次看到这样的文章我都会想到李舰和肖凯的<数据科学中的R语言>,书中一直强调,工具不 ...
- DAG最长路径
1.DAG最长路径(不记录路径) int dfs1(int s) { )return dis[s]; ; i < G[s].size(); ++i) { int to = G[s][i]; di ...
- 熟练使用Linux系统信息类命令
系统信息类命令 – dmesg命令 dmesg命令用实例名和物理名称来标识连到系统上的设备. dmesg命令显示系统诊断信息.操作系统版本号.物理内存大小以及其他信息. 系统启动时,屏幕上会显示系统C ...
- 关于在github上 下载源码 clone 非 master 分支的代码
https://blog.csdn.net/u012302552/article/details/80680497
- oracle事务知识点小结
DML语句流程 1 获取事务锁和ITL2 锁定候选行3 生成redo4 生成undo5 生成redo record写入log buffer并更改数据块 事务提交1 分配SCN2 更新事务表,将事务槽状 ...