使用用WCF中的双工(Duplex)模式将广告图片推送到每个Winform客户端机子上
参考资料地址:http://www.cnblogs.com/server126/archive/2011/08/11/2134942.html
代码实现:
WCF宿主(服务端)
IServices.cs 服务契约(其实就是接口)
namespace Host
{
[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallBackServices))]
public interface IServices
{
/// <summary>
/// 注册客户端信息
/// </summary>
[OperationContract(IsOneWay = false)]
void Register();
}
/// <summary>
/// 回调接口
/// </summary>
public interface ICallBackServices
{
/// <summary>
/// 服务像客户端发送信息(异步)
/// </summary>
/// <param name="Message"></param>
[OperationContract(IsOneWay = true)]
void SendMessage(string Message); /// <summary>
/// 服务端像客户端(异步)发送图片流
/// </summary>
/// <param name="messageEntity"></param>
[OperationContract(IsOneWay = true)]
void SendPicStream(MessageEntity messageEntity);
}
}
MessageEntity.cs 消息实体类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization; namespace WcfDuplex
{
/// <summary>
/// 消息实体类
/// </summary>
[DataContract]
public class MessageEntity
{
[DataMember]
public string Content { get; set; } [DataMember]
public byte[] PicStream { get; set; }
}
}
Services.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.Configuration; namespace Host
{
/// <summary>
/// 实例使用Single,共享一个
/// 并发使用Mutiple, 支持多线程访问(一定要加锁)
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class Services : IServices
{
public static readonly string SendMessageType = ConfigurationManager.ConnectionStrings["SendMessageType"].ToString();
private static readonly object InstObj = new object();//单一实例
//public static List<ICallBackServices> RegList = null;
public static Dictionary<string, ICallBackServices> DicHost = null; //记录机器名称
public static Dictionary<string, ICallBackServices> DicHostSess = null;//记录Sessionid
public Services()
{
//RegList = new List<ICallBackServices>();
DicHost = new Dictionary<string, ICallBackServices>();
DicHostSess = new Dictionary<string, ICallBackServices>();
}
#region IServices 成员 public void Register()
{
ICallBackServices client = OperationContext.Current.GetCallbackChannel<ICallBackServices>();
string sessionid = OperationContext.Current.SessionId;//获取当前机器Sessionid--------------------------如果多个客户端在同一台机器,就使用此信息。
string ClientHostName = OperationContext.Current.Channel.RemoteAddress.Uri.Host;//获取当前机器名称-----多个客户端不在同一台机器上,就使用此信息。
OperationContext.Current.Channel.Closing += new EventHandler(Channel_Closing);//注册客户端关闭触发事件
if (SendMessageType.ToUpper() == "SESSIONID")
{
DicHostSess.Add(sessionid, client);//添加
}
else
{
DicHost.Add(ClientHostName, client); //添加
}
//RegList.Add(client);//添加
}
void Channel_Closing(object sender, EventArgs e)
{
lock (InstObj)//加锁,处理并发
{
//if (RegList != null && RegList.Count > 0)
// RegList.Remove((ICallBackServices)sender);
if (SendMessageType.ToUpper() == "SESSIONID")
{
if (DicHostSess != null && DicHostSess.Count > )
{
foreach (var d in DicHostSess)
{
if (d.Value == (ICallBackServices)sender)//删除此关闭的客户端信息
{
DicHostSess.Remove(d.Key);
break;
}
}
}
}
else
{
if (DicHost != null && DicHost.Count > ) //同上
{
foreach (var d in DicHost)
{
if (d.Value == (ICallBackServices)sender)
{
DicHost.Remove(d.Key);
break;
}
}
}
}
}
}
#endregion
}
}
服务端

Form1.cs
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 System.Threading;
using WcfDuplex;
using System.IO; namespace Host
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private static readonly object InstObj = new object();
private static bool isval = true;
private void Form1_Load(object sender, EventArgs e)
{
ServiceHost host = new ServiceHost(typeof(Services));
host.Open();
this.Text = "wcf服务启动成功!"; #region 初始化ListBox
Thread thread = new Thread(new ThreadStart(delegate ///监听所有客户端连接,并添加到ListBox控件里
{
lock (InstObj)//加锁
{
while (true)
{ if (Services.SendMessageType.ToUpper() == "SESSIONID")
{
if (Services.DicHostSess != null || Services.DicHostSess.Count > )
{
this.Invoke(new MethodInvoker(delegate { this.listBox1.Items.Clear(); }));
foreach (var l in Services.DicHostSess)
{
this.Invoke(new MethodInvoker(delegate
{
this.listBox1.Items.Add(l.Key);
}));
}
}
}
else
{
if (Services.DicHost != null || Services.DicHost.Count > )
{
this.Invoke(new MethodInvoker(delegate { this.listBox1.Items.Clear(); }));
foreach (var l in Services.DicHost)
{
this.Invoke(new MethodInvoker(delegate
{
this.listBox1.Items.Add(l.Key);
}));
}
}
}
Thread.Sleep( * );
}
}
}));
thread.IsBackground = true;
thread.Start();
#endregion
} #region 推送
int i = ;
private void button1_Click(object sender, EventArgs e)
{
i++;
if (Services.DicHostSess == null || Services.DicHostSess.Count > )
{
if (this.listBox1.SelectedItem != null)
{
if (this.listBox1.SelectedItem.ToString() != "")
{
foreach (var d in Services.DicHostSess)
{
if (d.Key == this.listBox1.SelectedItem.ToString())
{
//d.Value.SendMessage(string.Format("Time: {0} message {1}", DateTime.Now, textBox1.Text.Trim()));
MessageEntity messageEntity = new MessageEntity();
if (i<)
{
string picPath = @"D:\download\wcf推送与广播\Host\Img\" + i + ".jpg";
messageEntity.PicStream = ImageDatabytes(picPath);
d.Value.SendPicStream(messageEntity);
}
}
}
}
}
else
{
MessageBox.Show("请选择要推送给哪台客户端");
i--;
return;
}
}
if (Services.DicHost != null || Services.DicHost.Count > )
{
if (this.listBox1.SelectedItem != null)
{
if (this.listBox1.SelectedItem.ToString() != "")
{
foreach (var d in Services.DicHost)
{
if (d.Key == this.listBox1.SelectedItem.ToString())
{
//d.Value.SendMessage(string.Format("Time: {0} message {1}", DateTime.Now, textBox1.Text.Trim()));
MessageEntity messageEntity = new MessageEntity();
if (i < )
{
string picPath = @"D:\download\wcf推送与广播\Host\Img\" + i + ".jpg";
messageEntity.PicStream = ImageDatabytes(picPath);
d.Value.SendPicStream(messageEntity);
}
}
}
}
}
else
{
MessageBox.Show("请选择要推送给哪台客户端");
i--;
return;
}
}
}
#endregion #region 广播方式
private void button2_Click(object sender, EventArgs e)
{
if (Services.SendMessageType.ToUpper() == "SESSIONID")//类型
{
foreach (var d in Services.DicHostSess)
{
d.Value.SendMessage(this.textBox1.Text);
}
}
else
{
foreach (var d in Services.DicHost)
{
d.Value.SendMessage(this.textBox1.Text);
}
}
}
#endregion #region 根据图片路径将图片转换为二进制流
/// <summary>
/// 根据图片路径将图片转换为二进制流
/// </summary>
/// <param name="FilePath"></param>
/// <returns></returns>
public static byte[] ImageDatabytes(string FilePath)
{
if (!File.Exists(FilePath))
return null;
Bitmap myBitmap = new Bitmap(Image.FromFile(FilePath)); using (MemoryStream curImageStream = new MemoryStream())
{
myBitmap.Save(curImageStream, System.Drawing.Imaging.ImageFormat.Png);
curImageStream.Flush(); byte[] bmpBytes = curImageStream.ToArray();
//如果转字符串的话
//string BmpStr = Convert.ToBase64String(bmpBytes);
return bmpBytes;
}
}
#endregion }
}
WinFormClient.cs 客户端



客户端Form1.cs
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.IO;
using System.ServiceModel; namespace WinFormClient
{ public partial class FormClient : Form
{
public FormClient()
{
InitializeComponent();
this.Text = "当前客户端编号为:"+DateTime.Now.ToString("yyyyMMddHHmmss");
try
{
Console.WriteLine("create object...");
CallBack back = new CallBack();
InstanceContext context = new InstanceContext(back);
ServiceReference1.ServicesClient client = new ServiceReference1.ServicesClient(context);
Console.WriteLine("regist.....");
back.showPic += new CallBack.ShowPic(ShowPicMethod);
client.Register();
Console.WriteLine("aucceeded");
//this.ReceivePic.Image = back.Pic;
}
catch (Exception ex) { Console.WriteLine(ex.Message); }
} public void ShowPicMethod(Bitmap bitmap)
{
this.ReceivePic.Image = bitmap;
}
} public class CallBack : ServiceReference1.IServicesCallback
{
public delegate void ShowPic(Bitmap bitmap);
public event ShowPic showPic; #region IServicesCallback 成员
public void SendMessage(string Message)
{
Console.WriteLine("[ClientTime{0:HHmmss}]Service Broadcast:{1}", DateTime.Now, Message);
} public void SendPicStream(ServiceReference1.MessageEntity messageEntity)
{
this.showPic(GetImage(messageEntity.PicStream));
}
#endregion #region 将图片二进制流转换为图片
public static Bitmap GetImage(byte[] ImageDatas)
{
try
{
//如果是字符串的话
//byte[] resultBytes = Convert.FromBase64String(ImageDatas);
using (MemoryStream ImageMS = new MemoryStream())
{
ImageMS.Write(ImageDatas, , ImageDatas.Length);
Bitmap resultBitmap = new Bitmap(ImageMS);
return resultBitmap;
}
}
catch
{
return null;
}
}
#endregion
}
}
Demo下载地址:http://files.cnblogs.com/files/wgx0428/wcf%E6%8E%A8%E9%80%81%E4%B8%8E%E5%B9%BF%E6%92%AD.zip
使用用WCF中的双工(Duplex)模式将广告图片推送到每个Winform客户端机子上的更多相关文章
- 我的WCF之旅(3):在WCF中实现双工通信
双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息.基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合.双工MEP又具 ...
- 在WCF中实现双工通信
双工(Duplex)模式的消息交换方式体现在消息交换过程中,参与的双方均可以向对方发送消息.基于双工MEP消息交换可以看成是多个基本模式下(比如请求-回复模式和单项模式)消息交换的组合.双工MEP又具 ...
- 【OF框架】在Azure DevOps中配置项目持续集成CI服务,推送镜像到Azure容器注册表
准备工作 开通Azure账号,具有开通服务权限,关键是里面要有钱. 开通Azure DevOps,能够创建组织和项目. 具备一定的DevOps知识,了解CICD概念.Docker基本操作. 一.创建& ...
- 用ASP.NET Core 1.0中实现邮件发送功能-阿里云邮件推送篇
在上篇中用MailKit实现了Asp.net core 邮件发送功能,但一直未解决阿里云邮件推送问题,提交工单一开始的回复不尽如人意,比如您的网络问题,您的用户名密码不正确等,但继续沟通下阿里云客户还 ...
- node.js中使用socket.io + express进行实时消息推送
socket.io是一个websocket库,包含客户端的js和服务端的node.js,可以在不同浏览器和移动设备上构建实时应用. 一.安装 socket.io npm install socket. ...
- 浅议Grpc传输机制和WCF中的回调机制的代码迁移
浅议Grpc传输机制和WCF中的回调机制的代码迁移 一.引子 如您所知,gRPC是目前比较常见的rpc框架,可以方便的作为服务与服务之间的通信基础设施,为构建微服务体系提供非常强有力的支持. 而基于. ...
- WCF初探-23:WCF中使用Message类(下)
前言 在上一篇WCF中使用Message类(上)中,文章介绍了WCF中使用Message类的基本知识和怎样创建消息,本文是承接上一篇文章,如果想要更好的阅读本文,请先阅读上一篇文章.在这篇文章中,我将 ...
- Android、iOS和Windows Phone中的推送技术
推送并不是什么新技术,这种技术在互联网时代就已经很流行了.只是随着进入移动互联网时代,推送技术显得更加重要.因为在智能手机中,推送从某种程度上,可以取代使用多年的短信,而且与短信相比,还可以向用户展示 ...
- APNS IOS 消息推送沙盒模式和发布模式
在做.NET向IOS设备的App进行消息推送时候,采用的是PushSharp开源类库进行消息的推送,而在开发过程中,采用的是测试版本的app,使用的是测试的p12证书采用的是ApnsConfigura ...
随机推荐
- 内核加载模块时提示usb_common: exports duplicate symbol of_usb_get_dr_mode
1.分析: 既然符号重复了,那么说明有一个部分既被编译到内核中也被编译成模块了,因此在加载模块时,内核报符号重复的提示 2.解决 直接配置内核的某一部分编译成模块,例如笔者就直接将USB这一部分编译成 ...
- Elasticsearch之中文分词器插件es-ik(博主推荐)
前提 什么是倒排索引? Elasticsearch之分词器的作用 Elasticsearch之分词器的工作流程 Elasticsearch之停用词 Elasticsearch之中文分词器 Elasti ...
- Android -- service的开启方式, start开启和绑定开启服务,调用服务的的方法, aidl调用远程服务
1. 概述 bindService() 绑定服务 可以得到服务的代理人对象,间接调用服务里面的方法. 绑定服务: 间接调用服务里面的方法. 如果调用者activity被销毁了, ...
- Qt5窗口标题栏高度
1.frameGeometry().height() - geometry().height() 2. QRect desktopRect = QApplication::desktop()-> ...
- FreeSouth的学习osg小贴士
http://www.osgchina.org/index.php?option=com_content&view=article&id=150&catid=91&It ...
- 《图解Http》 2-6章: 基础,报文,状态码,首部。
HTTP协议和Cookie 是stateless协议,自身不对请求和响应之间的通信状态进行保存.但随着技术发展,为了实现保存状态的功能,引入了Cookie技术. Cookie在请求和响应报文中写入信息 ...
- HDU - 4804 Campus Design 轮廓线dp
题意:一个nm的矩阵被12的骨牌和11的骨牌完全覆盖,11的骨牌只能放c-d次,矩阵中有障碍物 题解:dp[i][j][k]表示到了第i行,第j个状态,放过k个11的骨牌,当前位有障碍物时只有一种转移 ...
- Linux CentOS 6.5 使用自带jdk修改环境变量
首先声明,默认jdk指我们安装完CentOS后系统自带jdk,自己下载安装的jdk只需要下载,解压即可,之后步骤与此文一致 1.查看我们默认jdk的位置 指令: which java 我们去看一下发现 ...
- 菜鸟帮你跳过openstack配置过程中的坑[文末新添加福利]
一:前言 对于一个以前做java全栈工程师而言,而且没学过Linux,很少用虚拟机(还是在大学的时候简单的用过),去配置openstack我想我入的坑肯定比有基础的一定要多,躺在每个坑中徘徊思索的时间 ...
- 升级OPENSSH 和 OPENSSL
升级OPENSSH 和 OPENSSL 首先安装telnet服务,防止在操作过程中导致ssh远程中断 # 安装Telnetyum install telnet-server -y chkcon ...