分享WCF聊天程序--WCFChat
生活随笔
收集整理的這篇文章主要介紹了
分享WCF聊天程序--WCFChat
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
無意中在一個國外的站點下到了一個利用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?Dictionary<string,?ChatEventHandler>?chatters?=?new?Dictionary<string,?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.GetCallbackChannel<IChatCallback>();//獲取當前操作客戶端實例的通道給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?name="hWnd">其窗口程序將接收消息的窗口的句柄</param>///?<param?name="msg">指定被發送的消息</param>///?<param?name="wParam">指定附加的消息指定信息</param>///?<param?name="lParam">指定附加的消息指定信息</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?name="list"></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.Find<System.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總結
以上是生活随笔為你收集整理的分享WCF聊天程序--WCFChat的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 学习 WCF (6)--学习调用WCF服
- 下一篇: Java调用wcf