参考资料地址:
代码实现:
WCF宿主(服务端)
IServices.cs 服务契约(其实就是接口)
1 namespace Host 2 { 3 [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(ICallBackServices))] 4 public interface IServices 5 { 6 ///7 /// 注册客户端信息 8 /// 9 [OperationContract(IsOneWay = false)]10 void Register();11 }12 ///13 /// 回调接口14 /// 15 public interface ICallBackServices16 {17 ///18 /// 服务像客户端发送信息(异步)19 /// 20 /// 21 [OperationContract(IsOneWay = true)]22 void SendMessage(string Message);23 24 ///25 /// 服务端像客户端(异步)发送图片流26 /// 27 /// 28 [OperationContract(IsOneWay = true)]29 void SendPicStream(MessageEntity messageEntity);30 }31 }
MessageEntity.cs 消息实体类
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Web; 5 using System.Runtime.Serialization; 6 7 namespace WcfDuplex 8 { 9 ///10 /// 消息实体类11 /// 12 [DataContract]13 public class MessageEntity14 {15 [DataMember]16 public string Content { get; set; }17 18 [DataMember]19 public byte[] PicStream { get; set; }20 }21 }
Services.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.ServiceModel; 6 using System.Configuration; 7 8 namespace Host 9 {10 ///11 /// 实例使用Single,共享一个12 /// 并发使用Mutiple, 支持多线程访问(一定要加锁)13 /// 14 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]15 public class Services : IServices16 {17 public static readonly string SendMessageType = ConfigurationManager.ConnectionStrings["SendMessageType"].ToString();18 private static readonly object InstObj = new object();//单一实例19 //public static ListRegList = null;20 public static Dictionary DicHost = null; //记录机器名称21 public static Dictionary DicHostSess = null;//记录Sessionid22 public Services()23 {24 //RegList = new List ();25 DicHost = new Dictionary ();26 DicHostSess = new Dictionary ();27 }28 #region IServices 成员29 30 public void Register()31 {32 ICallBackServices client = OperationContext.Current.GetCallbackChannel ();33 string sessionid = OperationContext.Current.SessionId;//获取当前机器Sessionid--------------------------如果多个客户端在同一台机器,就使用此信息。34 string ClientHostName = OperationContext.Current.Channel.RemoteAddress.Uri.Host;//获取当前机器名称-----多个客户端不在同一台机器上,就使用此信息。35 OperationContext.Current.Channel.Closing += new EventHandler(Channel_Closing);//注册客户端关闭触发事件36 if (SendMessageType.ToUpper() == "SESSIONID")37 {38 DicHostSess.Add(sessionid, client);//添加39 }40 else41 {42 DicHost.Add(ClientHostName, client); //添加43 }44 //RegList.Add(client);//添加45 }46 void Channel_Closing(object sender, EventArgs e)47 {48 lock (InstObj)//加锁,处理并发49 {50 //if (RegList != null && RegList.Count > 0)51 // RegList.Remove((ICallBackServices)sender); 52 if (SendMessageType.ToUpper() == "SESSIONID")53 {54 if (DicHostSess != null && DicHostSess.Count > 0)55 {56 foreach (var d in DicHostSess)57 {58 if (d.Value == (ICallBackServices)sender)//删除此关闭的客户端信息59 {60 DicHostSess.Remove(d.Key);61 break;62 }63 }64 }65 }66 else67 {68 if (DicHost != null && DicHost.Count > 0) //同上69 {70 foreach (var d in DicHost)71 {72 if (d.Value == (ICallBackServices)sender)73 {74 DicHost.Remove(d.Key);75 break;76 }77 }78 }79 }80 }81 }82 #endregion83 }84 }
服务端
Form1.cs
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.ServiceModel; 10 using System.Threading; 11 using WcfDuplex; 12 using System.IO; 13 14 namespace Host 15 { 16 public partial class Form1 : Form 17 { 18 public Form1() 19 { 20 InitializeComponent(); 21 } 22 private static readonly object InstObj = new object(); 23 private static bool isval = true; 24 private void Form1_Load(object sender, EventArgs e) 25 { 26 ServiceHost host = new ServiceHost(typeof(Services)); 27 host.Open(); 28 this.Text = "wcf服务启动成功!"; 29 30 #region 初始化ListBox 31 Thread thread = new Thread(new ThreadStart(delegate ///监听所有客户端连接,并添加到ListBox控件里 32 { 33 lock (InstObj)//加锁 34 { 35 while (true) 36 { 37 38 if (Services.SendMessageType.ToUpper() == "SESSIONID") 39 { 40 if (Services.DicHostSess != null || Services.DicHostSess.Count > 0) 41 { 42 this.Invoke(new MethodInvoker(delegate { this.listBox1.Items.Clear(); })); 43 foreach (var l in Services.DicHostSess) 44 { 45 this.Invoke(new MethodInvoker(delegate 46 { 47 this.listBox1.Items.Add(l.Key); 48 })); 49 } 50 } 51 } 52 else 53 { 54 if (Services.DicHost != null || Services.DicHost.Count > 0) 55 { 56 this.Invoke(new MethodInvoker(delegate { this.listBox1.Items.Clear(); })); 57 foreach (var l in Services.DicHost) 58 { 59 this.Invoke(new MethodInvoker(delegate 60 { 61 this.listBox1.Items.Add(l.Key); 62 })); 63 } 64 } 65 } 66 Thread.Sleep(1000 * 10); 67 } 68 } 69 })); 70 thread.IsBackground = true; 71 thread.Start(); 72 #endregion 73 } 74 75 #region 推送 76 int i = 0; 77 private void button1_Click(object sender, EventArgs e) 78 { 79 i++; 80 if (Services.DicHostSess == null || Services.DicHostSess.Count > 0) 81 { 82 if (this.listBox1.SelectedItem != null) 83 { 84 if (this.listBox1.SelectedItem.ToString() != "") 85 { 86 foreach (var d in Services.DicHostSess) 87 { 88 if (d.Key == this.listBox1.SelectedItem.ToString()) 89 { 90 //d.Value.SendMessage(string.Format("Time: {0} message {1}", DateTime.Now, textBox1.Text.Trim())); 91 MessageEntity messageEntity = new MessageEntity(); 92 if (i<4) 93 { 94 string picPath = @"D:\download\wcf推送与广播\Host\Img\" + i + ".jpg"; 95 messageEntity.PicStream = ImageDatabytes(picPath); 96 d.Value.SendPicStream(messageEntity); 97 } 98 } 99 }100 }101 }102 else 103 { 104 MessageBox.Show("请选择要推送给哪台客户端");105 i--;106 return; 107 }108 }109 if (Services.DicHost != null || Services.DicHost.Count > 0)110 {111 if (this.listBox1.SelectedItem != null)112 {113 if (this.listBox1.SelectedItem.ToString() != "")114 {115 foreach (var d in Services.DicHost)116 {117 if (d.Key == this.listBox1.SelectedItem.ToString())118 {119 //d.Value.SendMessage(string.Format("Time: {0} message {1}", DateTime.Now, textBox1.Text.Trim()));120 MessageEntity messageEntity = new MessageEntity();121 if (i < 4)122 {123 string picPath = @"D:\download\wcf推送与广播\Host\Img\" + i + ".jpg";124 messageEntity.PicStream = ImageDatabytes(picPath);125 d.Value.SendPicStream(messageEntity);126 }127 }128 }129 }130 }131 else 132 { 133 MessageBox.Show("请选择要推送给哪台客户端");134 i--;135 return; 136 }137 }138 } 139 #endregion140 141 #region 广播方式142 private void button2_Click(object sender, EventArgs e)143 {144 if (Services.SendMessageType.ToUpper() == "SESSIONID")//类型145 {146 foreach (var d in Services.DicHostSess)147 {148 d.Value.SendMessage(this.textBox1.Text);149 }150 }151 else152 {153 foreach (var d in Services.DicHost)154 {155 d.Value.SendMessage(this.textBox1.Text);156 }157 }158 } 159 #endregion160 161 #region 根据图片路径将图片转换为二进制流162 ///163 /// 根据图片路径将图片转换为二进制流164 /// 165 /// 166 ///167 public static byte[] ImageDatabytes(string FilePath)168 {169 if (!File.Exists(FilePath))170 return null;171 Bitmap myBitmap = new Bitmap(Image.FromFile(FilePath));172 173 using (MemoryStream curImageStream = new MemoryStream())174 {175 myBitmap.Save(curImageStream, System.Drawing.Imaging.ImageFormat.Png);176 curImageStream.Flush();177 178 byte[] bmpBytes = curImageStream.ToArray();179 //如果转字符串的话180 //string BmpStr = Convert.ToBase64String(bmpBytes);181 return bmpBytes;182 }183 } 184 #endregion185 186 }187 }
WinFormClient.cs 客户端
客户端Form1.cs
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Drawing; 6 using System.Linq; 7 using System.Text; 8 using System.Windows.Forms; 9 using System.IO;10 using System.ServiceModel;11 12 namespace WinFormClient13 {14 15 16 public partial class FormClient : Form17 {18 public FormClient()19 {20 InitializeComponent();21 this.Text = "当前客户端编号为:"+DateTime.Now.ToString("yyyyMMddHHmmss");22 try23 {24 Console.WriteLine("create object...");25 CallBack back = new CallBack();26 InstanceContext context = new InstanceContext(back);27 ServiceReference1.ServicesClient client = new ServiceReference1.ServicesClient(context);28 Console.WriteLine("regist.....");29 back.showPic += new CallBack.ShowPic(ShowPicMethod);30 client.Register();31 Console.WriteLine("aucceeded");32 //this.ReceivePic.Image = back.Pic;33 }34 catch (Exception ex) { Console.WriteLine(ex.Message); }35 }36 37 public void ShowPicMethod(Bitmap bitmap)38 {39 this.ReceivePic.Image = bitmap;40 }41 }42 43 public class CallBack : ServiceReference1.IServicesCallback44 {45 public delegate void ShowPic(Bitmap bitmap);46 public event ShowPic showPic;47 48 #region IServicesCallback 成员49 public void SendMessage(string Message)50 {51 Console.WriteLine("[ClientTime{0:HHmmss}]Service Broadcast:{1}", DateTime.Now, Message);52 }53 54 public void SendPicStream(ServiceReference1.MessageEntity messageEntity)55 {56 this.showPic(GetImage(messageEntity.PicStream));57 }58 #endregion59 60 #region 将图片二进制流转换为图片61 public static Bitmap GetImage(byte[] ImageDatas)62 {63 try64 {65 //如果是字符串的话66 //byte[] resultBytes = Convert.FromBase64String(ImageDatas);67 using (MemoryStream ImageMS = new MemoryStream())68 {69 ImageMS.Write(ImageDatas, 0, ImageDatas.Length);70 Bitmap resultBitmap = new Bitmap(ImageMS);71 return resultBitmap;72 }73 }74 catch75 {76 return null;77 }78 }79 #endregion80 }81 }
Demo下载地址:http://files.cnblogs.com/files/wgx0428/wcf%E6%8E%A8%E9%80%81%E4%B8%8E%E5%B9%BF%E6%92%AD.zip