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实现消息推送的更多相关文章

  1. SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=》提升)

     SignalR快速入门 ~ 仿QQ即时聊天,消息推送,单聊,群聊,多群公聊(基础=>提升,5个Demo贯彻全篇,感兴趣的玩才是真的学) 官方demo:http://www.asp.net/si ...

  2. 【原创分享·微信支付】C# MVC 微信支付之微信模板消息推送

    微信支付之微信模板消息推送                    今天我要跟大家分享的是“模板消息”的推送,这玩意呢,你说用途嘛,那还是真真的牛逼呐.原因在哪?就是因为它是依赖微信生存的呀,所以他能不 ...

  3. 基于SignalR的消息推送与二维码描登录实现

    1 概要说明 使用微信扫描登录相信大家都不会陌生吧,二维码与手机结合产生了不同应用场景,基于二维码的应用更是比较广泛.为了满足ios.android客户端与web短信平台的结合,特开发了基于Singl ...

  4. C# BS消息推送 SignalR介绍(一)

    1. 前言 本文是根据网上前人的总结得出的. 环境: SignalR2.x,VS2015,Win10 介绍 1)SignalR能用来持久客户端与服务端的连接,让我们便于开发一些实时的应用,例如聊天室在 ...

  5. iOS 之消息推送(个推)---个人小结

    前言:自从上个星期开始整这个推送,弄了差不多一个星期,今天终于给整好了,因此现在来记录这段"奇妙"的旅程. 我们公司使用的消息推送是用的第三方--个推,这里不得不说一下,个推的技术 ...

  6. WebSocket与消息推送

    B/S结构的软件项目中有时客户端需要实时的获得服务器消息,但默认HTTP协议只支持请求响应模式,这样做可以简化Web服务器,减少服务器的负担,加快响应速度,因为服务器不需要与客户端长时间建立一个通信链 ...

  7. 分分钟搞定IOS远程消息推送

    一.引言 IOS中消息的推送有两种方式,分别是本地推送和远程推送,本地推送在http://my.oschina.net/u/2340880/blog/405491这篇博客中有详细的介绍,这里主要讨论远 ...

  8. 基于ajax与msmq技术的消息推送功能实现

    周末在家捣鼓了一下消息推送的简单例子,其实也没什么技术含量,欢迎大伙拍砖.我设计的这个推送demo是基于ajax长轮询+msmq消息队列来实现的,具体交互过程如下图: 先说说这个ajax长轮询,多长时 ...

  9. C# BS消息推送 SignalR Hubs环境搭建与开发(二)

    1. 前言 本文是根据网上前人的总结得出的. 环境: SignalR2.x,VS2015,Win10 2. 开始开发 1)新建一个MVC项目,叫做SignalRDemo 2)安装SignalR包 In ...

随机推荐

  1. 【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 ...

  2. 全面剖析Smarty缓存机制一[三种缓存方式]

    今天主要全面总结下Smarty模板引擎中强大的缓存机制,缓存机制有效减少了系统对服务器的压力,而这也是很多开发者喜欢Smarty的原因之一,由于篇幅较大,便于博友阅读,这篇文章将剖析Smarty缓存的 ...

  3. FastAdmin 插件配置文件 info.ini 中的 state 什么意思?

    FastAdmin 插件配置文件 info.ini 中的 state 什么意思? 在插件配置中有一个 state ,这是配置插件开关的.

  4. SQL Server中的事务与其隔离级别之脏读, 未提交读,不可重复读和幻读

    原本打算写有关 SSIS Package 中的事务控制过程的,但是发现很多基本的概念还是需要有 SQL Server 事务和事务的隔离级别做基础铺垫.所以花了点时间,把 SQL Server 数据库中 ...

  5. 在Linux中安装Oracle(较详细图解)

    原创 http://www.cnblogs.com/nucdy/p/5603998.html 参考视屏:链接: https://pan.baidu.com/s/1kViEZQZ  密码: z7ha ( ...

  6. Python调用R语言

    网络上经常看到有人问数据分析是学习Python好还是R语言好,还有一些争论Python好还是R好的文章.每次看到这样的文章我都会想到李舰和肖凯的<数据科学中的R语言>,书中一直强调,工具不 ...

  7. DAG最长路径

    1.DAG最长路径(不记录路径) int dfs1(int s) { )return dis[s]; ; i < G[s].size(); ++i) { int to = G[s][i]; di ...

  8. 熟练使用Linux系统信息类命令

    系统信息类命令 – dmesg命令 dmesg命令用实例名和物理名称来标识连到系统上的设备. dmesg命令显示系统诊断信息.操作系统版本号.物理内存大小以及其他信息. 系统启动时,屏幕上会显示系统C ...

  9. 关于在github上 下载源码 clone 非 master 分支的代码

    https://blog.csdn.net/u012302552/article/details/80680497

  10. oracle事务知识点小结

    DML语句流程 1 获取事务锁和ITL2 锁定候选行3 生成redo4 生成undo5 生成redo record写入log buffer并更改数据块 事务提交1 分配SCN2 更新事务表,将事务槽状 ...