斗门区住房和城乡建设网站,网站建设完整版,惠州网站建设找哪个公司,软件开发工具的基本功能有哪些无意中在一个国外的站点下到了一个利用WCF实现聊天的程序#xff0c;作者是#xff1a;Nikola Paljetak。研究了一下#xff0c;自己做了测试和部分修改#xff0c;感觉还不错#xff0c;分享给大家。先来看下运行效果#xff1a;开启服务#xff1a;客户端程序#xf…无意中在一个国外的站点下到了一个利用WCF实现聊天的程序作者是Nikola Paljetak。研究了一下自己做了测试和部分修改感觉还不错分享给大家。先来看下运行效果开启服务客户端程序程序分为客户端和服务器端------------服务器端 IChatService.cs: Codeusing System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;using System.Collections;namespace WCFChatService{ // SessionMode.Required 允许Session会话。双工协定时的回调协定类型为IChatCallback接口 [ServiceContract(SessionMode SessionMode.Required, CallbackContract typeof(IChatCallback))] public interface IChatService { [OperationContract(IsOneWay false, IsInitiating true, IsTerminating false)]//-----IsOneWay false等待服务器完成对方法处理;IsInitiating true启动Session会话,IsTerminating false 设置服务器发送回复后不关闭会话 string[] Join(string name);//用户加入 [OperationContract(IsOneWay true, IsInitiating false, IsTerminating false)] void Say(string msg);//群聊信息 [OperationContract(IsOneWay true, IsInitiating false, IsTerminating false)] void Whisper(string to, string msg);//私聊信息 [OperationContract(IsOneWay true, IsInitiating false, IsTerminating true)] void Leave();//用户加入 } /// summary /// 双向通信的回调接口 /// /summary interface IChatCallback { [OperationContract(IsOneWay true)] void Receive(string senderName, string message); [OperationContract(IsOneWay true)] void ReceiveWhisper(string senderName, string message); [OperationContract(IsOneWay true)] void UserEnter(string name); [OperationContract(IsOneWay true)] void UserLeave(string name); } /// summary /// 设定消息的类型 /// /summary public enum MessageType { Receive, UserEnter, UserLeave, ReceiveWhisper }; /// summary /// 定义一个本例的事件消息类. 创建包含有关事件的其他有用的信息的变量只要派生自EventArgs即可。 /// /summary public class ChatEventArgs : EventArgs { public MessageType msgType; public string name; public string message; }} ChatService.cs Codeusing System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;namespace WCFChatService{ // InstanceContextMode.PerSession 服务器为每个客户会话创建一个新的上下文对象。ConcurrencyMode.Multiple 异步的多线程实例 [ServiceBehavior(InstanceContextMode InstanceContextMode.PerSession, ConcurrencyMode ConcurrencyMode.Multiple)] public class ChatService : IChatService { private static Object syncObj new Object();////定义一个静态对象用于线程部份代码块的锁定用于lock操作 IChatCallback callback null; public delegate void ChatEventHandler(object sender, ChatEventArgs e);//定义用于把处理程序赋予给事件的委托。 public static event ChatEventHandler ChatEvent;//定义事件 static Dictionarystring, ChatEventHandler chatters new Dictionarystring, ChatEventHandler();//创建一个静态Dictionary表示键和值集合(字典)用于记录在线成员Dictionary(Of (TKey, TValue)) 泛型类 private string name; private ChatEventHandler myEventHandler null; public string[] Join(string name) { bool userAdded false; myEventHandler new ChatEventHandler(MyEventHandler);//将MyEventHandler方法作为参数传递给委托 lock (syncObj)//线程的同步性同步访问多个线程的任何变量利用lock(独占锁)确保数据访问的唯一性。 { if (!chatters.ContainsKey(name) name ! name ! null) { this.name name; chatters.Add(name, MyEventHandler); userAdded true; } } if (userAdded) { callback OperationContext.Current.GetCallbackChannelIChatCallback();//获取当前操作客户端实例的通道给IChatCallback接口的实例callback,此通道是一个定义为IChatCallback类型的泛类型,通道的类型是事先服务契约协定好的双工机制。 ChatEventArgs e new ChatEventArgs();//实例化事件消息类ChatEventArgs e.msgType MessageType.UserEnter; e.name name; BroadcastMessage(e); ChatEvent myEventHandler; string[] list new string[chatters.Count]; //以下代码返回当前进入聊天室成员的称列表 lock (syncObj) { chatters.Keys.CopyTo(list, 0);//将字典中记录的用户信息复制到数组中返回。 } return list; } else { return null; } } public void Say(string msg) { ChatEventArgs e new ChatEventArgs(); e.msgType MessageType.Receive; e.name this.name; e.message msg; BroadcastMessage(e); } public void Whisper(string to, string msg) { ChatEventArgs e new ChatEventArgs(); e.msgType MessageType.ReceiveWhisper; e.name this.name; e.message msg; try { ChatEventHandler chatterTo;//创建一个临时委托实例 lock (syncObj) { chatterTo chatters[to]; //查找成员字典中找到要接收者的委托调用 } chatterTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);//异步方式调用接收者的委托调用 } catch (KeyNotFoundException) { } } public void Leave() { if (this.name null) return; lock (syncObj) { chatters.Remove(this.name); } ChatEvent - myEventHandler; ChatEventArgs e new ChatEventArgs(); e.msgType MessageType.UserLeave; e.name this.name; this.name null; BroadcastMessage(e); } //回调根据客户端动作通知对应客户端执行对应的操作 private void MyEventHandler(object sender, ChatEventArgs e) { try { switch (e.msgType) { case MessageType.Receive: callback.Receive(e.name, e.message); break; case MessageType.ReceiveWhisper: callback.ReceiveWhisper(e.name, e.message); break; case MessageType.UserEnter: callback.UserEnter(e.name); break; case MessageType.UserLeave: callback.UserLeave(e.name); break; } } catch { Leave(); } } private void BroadcastMessage(ChatEventArgs e) { ChatEventHandler temp ChatEvent; if (temp ! null) { //循环将在线的用户广播信息 foreach (ChatEventHandler handler in temp.GetInvocationList()) { //异步方式调用多路广播委托的调用列表中的ChatEventHandler handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null); } } } //广播中线程调用完成的回调方法功能清除异常多路广播委托的调用列表中异常对象空对象 private void EndAsync(IAsyncResult ar) { ChatEventHandler d null; try { //封装异步委托上的异步操作结果 System.Runtime.Remoting.Messaging.AsyncResult asres (System.Runtime.Remoting.Messaging.AsyncResult)ar; d ((ChatEventHandler)asres.AsyncDelegate); d.EndInvoke(ar); } catch { ChatEvent - d; } } }} ------------客户端 Codeusing 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.Runtime.InteropServices;using System.ServiceModel;namespace WCFChatClient{ public partial class ChatForm : Form, IChatServiceCallback { /// summary /// 该函数将指定的消息发送到一个或多个窗口。此函数为指定的窗口调用窗口程序直到窗口程序处理完消息再返回。 /// /summary /// param namehWnd其窗口程序将接收消息的窗口的句柄/param /// param namemsg指定被发送的消息/param /// param namewParam指定附加的消息指定信息/param /// param namelParam指定附加的消息指定信息/param [DllImport(user32.dll)] private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam); //当一个窗口标准垂直滚动条产生一个滚动事件时发送此消息给那个窗口也发送给拥有它的控件 private const int WM_VSCROLL 0x115; private const int SB_BOTTOM 7; private int lastSelectedIndex -1; private ChatServiceClient proxy; private string userName; private WaitForm wfDlg new WaitForm(); private delegate void HandleDelegate(string[] list); private delegate void HandleErrorDelegate(); public ChatForm() { InitializeComponent(); ShowInterChatMenuItem(true); } /// summary /// 连接服务器 /// /summary private void InterChatMenuItem_Click(object sender, EventArgs e) { lbOnlineUsers.Items.Clear(); LoginForm loginDlg new LoginForm(); if (loginDlg.ShowDialog() DialogResult.OK) { userName loginDlg.txtUserName.Text; loginDlg.Close(); } txtChatContent.Focus(); Application.DoEvents(); InstanceContext site new InstanceContext(this);//为实现服务实例的对象进行初始化 proxy new ChatServiceClient(site); IAsyncResult iar proxy.BeginJoin(userName, new AsyncCallback(OnEndJoin), null); wfDlg.ShowDialog(); } private void OnEndJoin(IAsyncResult iar) { try { string[] list proxy.EndJoin(iar); HandleEndJoin(list); } catch (Exception e) { HandleEndJoinError(); } } /// summary /// 错误提示 /// /summary private void HandleEndJoinError() { if (wfDlg.InvokeRequired) wfDlg.Invoke(new HandleErrorDelegate(HandleEndJoinError)); else { wfDlg.ShowError(无法连接聊天室!); ExitChatSession(); } } /// summary /// 登录结束后的处理 /// /summary /// param namelist/param private void HandleEndJoin(string[] list) { if (wfDlg.InvokeRequired) wfDlg.Invoke(new HandleDelegate(HandleEndJoin), new object[] { list }); else { wfDlg.Visible false; ShowInterChatMenuItem(false); foreach (string name in list) { lbOnlineUsers.Items.Add(name); } AppendText( 用户: userName --------登录--------- DateTime.Now.ToString() Environment.NewLine); } } /// summary /// 退出聊天室 /// /summary private void OutInterChatMenuItem_Click(object sender, EventArgs e) { ExitChatSession(); Application.Exit(); } /// summary /// 群聊 /// /summary private void btnChat_Click(object sender, EventArgs e) { SayAndClear(, txtChatContent.Text, false); txtChatContent.Focus(); } /// summary /// 发送消息 /// /summary private void SayAndClear(string to, string msg, bool pvt) { if (msg ! ) { try { CommunicationState cs proxy.State; //pvt 公聊还是私聊 if (!pvt) { proxy.Say(msg); } else { proxy.Whisper(to, msg); } txtChatContent.Text ; } catch { AbortProxyAndUpdateUI(); AppendText(失去连接 DateTime.Now.ToString() Environment.NewLine); ExitChatSession(); } } } private void txtChatContent_KeyPress(object sender, KeyPressEventArgs e) { if (e.KeyChar 13) { e.Handled true; btnChat.PerformClick(); } } /// summary /// 只有选择一个用户时私聊按钮才可用 /// /summary private void lbOnlineUsers_SelectedIndexChanged(object sender, EventArgs e) { AdjustWhisperButton(); } /// summary /// 私聊 /// /summary private void btnWhisper_Click(object sender, EventArgs e) { if (txtChatDetails.Text ) { return; } object to lbOnlineUsers.SelectedItem; if (to ! null) { string receiverName (string)to; AppendText(私下对 receiverName 说: txtChatContent.Text);// Environment.NewLine SayAndClear(receiverName, txtChatContent.Text, true); txtChatContent.Focus(); } } /// summary /// 连接聊天室 /// /summary private void ShowInterChatMenuItem(bool show) { InterChatMenuItem.Enabled show; OutInterChatMenuItem.Enabled this.btnChat.Enabled !show; } private void AppendText(string text) { txtChatDetails.Text text; SendMessage(txtChatDetails.Handle, WM_VSCROLL, SB_BOTTOM, new IntPtr(0)); } /// summary /// 退出应用程序时,释放使用资源 /// /summary private void ExitChatSession() { try { proxy.Leave(); } catch { } finally { AbortProxyAndUpdateUI(); } } /// summary /// 释放使用资源 /// /summary private void AbortProxyAndUpdateUI() { if (proxy ! null) { proxy.Abort(); proxy.Close(); proxy null; } ShowInterChatMenuItem(true); } /// summary /// 接收消息 /// /summary public void Receive(string senderName, string message) { AppendText(senderName 说: message Environment.NewLine); } /// summary /// 接收私聊消息 /// /summary public void ReceiveWhisper(string senderName, string message) { AppendText(senderName 私下说: message Environment.NewLine); } /// summary /// 新用户登录 /// /summary public void UserEnter(string name) { AppendText(用户 name --------登录--------- DateTime.Now.ToString() Environment.NewLine); lbOnlineUsers.Items.Add(name); } /// summary /// 用户离开 /// /summary public void UserLeave(string name) { AppendText(用户 name --------离开--------- DateTime.Now.ToString() Environment.NewLine); lbOnlineUsers.Items.Remove(name); AdjustWhisperButton(); } /// summary /// 控制私聊按钮的可用性,只有选择了用户时按钮才可用 /// /summary private void AdjustWhisperButton() { if (lbOnlineUsers.SelectedIndex lastSelectedIndex) { lbOnlineUsers.SelectedIndex -1; lastSelectedIndex -1; btnWhisper.Enabled false; } else { btnWhisper.Enabled true; lastSelectedIndex lbOnlineUsers.SelectedIndex; } txtChatContent.Focus(); } /// summary /// 窗体关闭时释放使用资源 /// /summary private void ChatForm_FormClosed(object sender, FormClosedEventArgs e) { AbortProxyAndUpdateUI(); Application.Exit(); } }} 代码中我做了详细的讲解相信园友们完全可以看懂。代码中的一些使用的方法还是值得大家参考学习的。这里涉及到了WCF的使用方法需要注意的是:如果想利用工具生成代理类需要加上下面的代码 Codeif (host.Description.Behaviors.FindSystem.ServiceModel.Description.ServiceMetadataBehavior() null) { BindingElement metaElement new TcpTransportBindingElement(); CustomBinding metaBind new CustomBinding(metaElement); host.Description.Behaviors.Add(new System.ServiceModel.Description.ServiceMetadataBehavior()); host.AddServiceEndpoint(typeof(System.ServiceModel.Description.IMetadataExchange), metaBind, MEX); } 否则在生成代理类的时候会报错如下的错误源码下载/Files/gaoweipeng/WCFChat.rar 转载于:https://www.cnblogs.com/soundcode/archive/2011/08/08/2131113.html