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. socket编程---UDP

    头文件 #include <sys/types.h> #include <sys/socket.h> 函数原型 int sendto (int s, const void *b ...

  2. jQuqery append 和 after 区别

    jQuqery append 和 after 区别 append 是在被选元素内的结尾插入内容. 比如以下选中了 ol 元素,使用 append 后会在 <li> List Item 2 ...

  3. 生成.eps文件方法

    生成.eps文件方法 背景: 要写论文了,图像的分辨率是一大痛点 方法一: 两步生成.eps文件 用visio 制作图形,保存为pdf格式: 直接用adobe acrobat 打开pdf,然后保存为. ...

  4. 静态链接ffmpeg库注意的问题(转)

    1. 最近使用ffmpeg静态库进行链接,提示 undefined reference,排查发现静态库的顺序导致的,静态库对先后顺序有严格要求 2. 使用ffmpeg库时,在链接时,需要加上-lm - ...

  5. 指向NULL的类

    引出:写个类A,声明类A指针指向NULL,调用类A的方法会有什么后果,编译通过吗,运行会通过吗? (在VS2008与VC++的情况下) 有错误欢迎批评指正! #include<stdio.h&g ...

  6. CentOS查看显卡及GPU相关信息

    lspci  | grep -i vga 这样就可以显示机器上的显卡信息,比如 [root@localhost conf]# lspci | grep -i vga01:00.0 VGA compat ...

  7. wchar_t char string wstring 之间的转换

    wchar_t char string wstring 之间的转换 转:http://blog.csdn.net/lbd2008/article/details/8333583 在处理中文时有时需要进 ...

  8. springMvc上传文件、读取zip/rar文件

    参考文章: http://www.cnblogs.com/interdrp/p/6734033.html 方法一: 1)没有配置org.springframework.web.multipart.co ...

  9. Flask框架的学习与实战(一):开发环境搭建

    Flask是一个使用 Python 编写的轻量级 Web 应用框架.其 WSGI 工具箱采用 Werkzeug ,模板引擎则使用 Jinja2.很多功能的实现都参考了django框架.由于项目需要,在 ...

  10. C#调用Oracle带输出数据集的存储过程

    1.创建一个带输出数据集的Oracle存储过程 create or replace procedure PRO_test(in_top in number,cur_out out sys_refcur ...