国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C# > 正文

分享WCF聊天程序--WCFChat實現代碼

2019-10-29 21:36:26
字體:
來源:轉載
供稿:網友

無意中在一個國外的站點下到了一個利用WCF實現聊天的程序,作者是:Nikola Paljetak。研究了一下,自己做了測試和部分修改,感覺還不錯,分享給大家。

先來看下運行效果:

開啟服務:

分享WCF聊天程序--WCFChat實現代碼

客戶端程序:

分享WCF聊天程序--WCFChat實現代碼

分享WCF聊天程序--WCFChat實現代碼

程序分為客戶端和服務器端:

------------服務器端:

IChatService.cs:

 

 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Runtime.Serialization; 
  5. using System.ServiceModel; 
  6. using System.Text; 
  7. using System.Collections; 
  8.  
  9. namespace WCFChatService 
  10. // SessionMode.Required 允許Session會話。雙工協定時的回調協定類型為IChatCallback接口 
  11. [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IChatCallback))] 
  12. public interface IChatService 
  13. [OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]//----->IsOneWay = false等待服務器完成對方法處理;IsInitiating = true啟動Session會話,IsTerminating = false 設置服務器發送回復后不關閉會話 
  14. string[] Join(string name);//用戶加入 
  15.  
  16. [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)] 
  17. void Say(string msg);//群聊信息 
  18.  
  19. [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = false)] 
  20. void Whisper(string to, string msg);//私聊信息 
  21.  
  22. [OperationContract(IsOneWay = true, IsInitiating = false, IsTerminating = true)] 
  23. void Leave();//用戶加入 
  24. /// <summary> 
  25. /// 雙向通信的回調接口 
  26. /// </summary> 
  27. interface IChatCallback 
  28. [OperationContract(IsOneWay = true)] 
  29. void Receive(string senderName, string message); 
  30.  
  31. [OperationContract(IsOneWay = true)] 
  32. void ReceiveWhisper(string senderName, string message); 
  33.  
  34. [OperationContract(IsOneWay = true)] 
  35. void UserEnter(string name); 
  36.  
  37. [OperationContract(IsOneWay = true)] 
  38. void UserLeave(string name); 
  39.  
  40. /// <summary> 
  41. /// 設定消息的類型 
  42. /// </summary> 
  43. public enum MessageType { Receive, UserEnter, UserLeave, ReceiveWhisper }; 
  44. /// <summary> 
  45. /// 定義一個本例的事件消息類. 創建包含有關事件的其他有用的信息的變量,只要派生自EventArgs即可。 
  46. /// </summary> 
  47. public class ChatEventArgs : EventArgs 
  48. public MessageType msgType; 
  49. public string name; 
  50. public string message; 

ChatService.cs

 

 
  1. using System; 
  2. using System.Collections.Generic; 
  3. using System.Linq; 
  4. using System.Runtime.Serialization; 
  5. using System.ServiceModel; 
  6. using System.Text; 
  7.  
  8. namespace WCFChatService 
  9. // InstanceContextMode.PerSession 服務器為每個客戶會話創建一個新的上下文對象。ConcurrencyMode.Multiple 異步的多線程實例 
  10. [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)] 
  11. public class ChatService : IChatService 
  12. private static Object syncObj = new Object();////定義一個靜態對象用于線程部份代碼塊的鎖定,用于lock操作 
  13. IChatCallback callback = null
  14.  
  15. public delegate void ChatEventHandler(object sender, ChatEventArgs e);//定義用于把處理程序賦予給事件的委托。 
  16. public static event ChatEventHandler ChatEvent;//定義事件 
  17. static Dictionary<string, ChatEventHandler> chatters = new Dictionary<string, ChatEventHandler>();//創建一個靜態Dictionary(表示鍵和值)集合(字典),用于記錄在線成員,Dictionary<(Of <(TKey, TValue>)>) 泛型類 
  18.  
  19. private string name; 
  20. private ChatEventHandler myEventHandler = null
  21.  
  22.  
  23. public string[] Join(string name) 
  24. bool userAdded = false
  25. myEventHandler = new ChatEventHandler(MyEventHandler);//將MyEventHandler方法作為參數傳遞給委托 
  26.  
  27. lock (syncObj)//線程的同步性,同步訪問多個線程的任何變量,利用lock(獨占鎖),確保數據訪問的唯一性。 
  28. if (!chatters.ContainsKey(name) && name != "" && name != null
  29. this.name = name; 
  30. chatters.Add(name, MyEventHandler); 
  31. userAdded = true
  32.  
  33. if (userAdded) 
  34. callback = OperationContext.Current.GetCallbackChannel<IChatCallback>();//獲取當前操作客戶端實例的通道給IChatCallback接口的實例callback,此通道是一個定義為IChatCallback類型的泛類型,通道的類型是事先服務契約協定好的雙工機制。 
  35. ChatEventArgs e = new ChatEventArgs();//實例化事件消息類ChatEventArgs 
  36. e.msgType = MessageType.UserEnter; 
  37. e.name = name; 
  38. BroadcastMessage(e); 
  39. ChatEvent += myEventHandler; 
  40. string[] list = new string[chatters.Count]; //以下代碼返回當前進入聊天室成員的稱列表 
  41. lock (syncObj) 
  42. chatters.Keys.CopyTo(list, 0);//將字典中記錄的用戶信息復制到數組中返回。 
  43. return list; 
  44. else 
  45. return null
  46.  
  47. public void Say(string msg) 
  48. ChatEventArgs e = new ChatEventArgs(); 
  49. e.msgType = MessageType.Receive; 
  50. e.name = this.name; 
  51. e.message = msg; 
  52. BroadcastMessage(e); 
  53.  
  54. public void Whisper(string to, string msg) 
  55. ChatEventArgs e = new ChatEventArgs(); 
  56. e.msgType = MessageType.ReceiveWhisper; 
  57. e.name = this.name; 
  58. e.message = msg; 
  59. try 
  60. ChatEventHandler chatterTo;//創建一個臨時委托實例 
  61. lock (syncObj) 
  62. chatterTo = chatters[to]; //查找成員字典中,找到要接收者的委托調用 
  63. chatterTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);//異步方式調用接收者的委托調用 
  64. catch (KeyNotFoundException) 
  65.  
  66. public void Leave() 
  67. if (this.name == null
  68. return
  69.  
  70. lock (syncObj) 
  71. chatters.Remove(this.name); 
  72. ChatEvent -= myEventHandler; 
  73. ChatEventArgs e = new ChatEventArgs(); 
  74. e.msgType = MessageType.UserLeave; 
  75. e.name = this.name; 
  76. this.name = null
  77. BroadcastMessage(e); 
  78.  
  79. //回調,根據客戶端動作通知對應客戶端執行對應的操作 
  80. private void MyEventHandler(object sender, ChatEventArgs e) 
  81. try 
  82. switch (e.msgType) 
  83. case MessageType.Receive: 
  84. callback.Receive(e.name, e.message); 
  85. break
  86. case MessageType.ReceiveWhisper: 
  87. callback.ReceiveWhisper(e.name, e.message); 
  88. break
  89. case MessageType.UserEnter: 
  90. callback.UserEnter(e.name); 
  91. break
  92. case MessageType.UserLeave: 
  93. callback.UserLeave(e.name); 
  94. break
  95. catch 
  96. Leave(); 
  97.  
  98. private void BroadcastMessage(ChatEventArgs e) 
  99.  
  100. ChatEventHandler temp = ChatEvent; 
  101.  
  102. if (temp != null
  103. //循環將在線的用戶廣播信息 
  104. foreach (ChatEventHandler handler in temp.GetInvocationList()) 
  105. //異步方式調用多路廣播委托的調用列表中的ChatEventHandler  
  106. handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null); 
  107. //廣播中線程調用完成的回調方法功能:清除異常多路廣播委托的調用列表中異常對象(空對象) 
  108. private void EndAsync(IAsyncResult ar) 
  109. ChatEventHandler d = null
  110.  
  111. try 
  112. //封裝異步委托上的異步操作結果 
  113. System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar; 
  114. d = ((ChatEventHandler)asres.AsyncDelegate); 
  115. d.EndInvoke(ar); 
  116. catch 
  117. ChatEvent -= d; 

------------客戶端:

 

 
  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.Runtime.InteropServices; 
  10. using System.ServiceModel; 
  11.  
  12. namespace WCFChatClient 
  13. public partial class ChatForm : Form, IChatServiceCallback 
  14. /// <summary> 
  15. /// 該函數將指定的消息發送到一個或多個窗口。此函數為指定的窗口調用窗口程序,直到窗口程序處理完消息再返回。  
  16. /// </summary> 
  17. /// <param name="hWnd">其窗口程序將接收消息的窗口的句柄</param> 
  18. /// <param name="msg">指定被發送的消息</param> 
  19. /// <param name="wParam">指定附加的消息指定信息</param> 
  20. /// <param name="lParam">指定附加的消息指定信息</param> 
  21. [DllImport("user32.dll")] 
  22. private static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam); 
  23. //當一個窗口標準垂直滾動條產生一個滾動事件時發送此消息給那個窗口,也發送給擁有它的控件 
  24. private const int WM_VSCROLL = 0x115; 
  25. private const int SB_BOTTOM = 7; 
  26. private int lastSelectedIndex = -1; 
  27.  
  28. private ChatServiceClient proxy; 
  29. private string userName; 
  30.  
  31. private WaitForm wfDlg = new WaitForm(); 
  32. private delegate void HandleDelegate(string[] list); 
  33. private delegate void HandleErrorDelegate(); 
  34.  
  35. public ChatForm() 
  36. InitializeComponent(); 
  37. ShowInterChatMenuItem(true); 
  38.  
  39. /// <summary> 
  40. /// 連接服務器 
  41. /// </summary> 
  42. private void InterChatMenuItem_Click(object sender, EventArgs e) 
  43. lbOnlineUsers.Items.Clear(); 
  44. LoginForm loginDlg = new LoginForm(); 
  45. if (loginDlg.ShowDialog() == DialogResult.OK) 
  46. userName = loginDlg.txtUserName.Text; 
  47. loginDlg.Close(); 
  48.  
  49. txtChatContent.Focus(); 
  50. Application.DoEvents(); 
  51. InstanceContext site = new InstanceContext(this);//為實現服務實例的對象進行初始化 
  52. proxy = new ChatServiceClient(site); 
  53. IAsyncResult iar = proxy.BeginJoin(userName, new AsyncCallback(OnEndJoin), null); 
  54. wfDlg.ShowDialog(); 
  55.  
  56. private void OnEndJoin(IAsyncResult iar) 
  57. try 
  58. string[] list = proxy.EndJoin(iar); 
  59. HandleEndJoin(list); 
  60.  
  61. catch (Exception e) 
  62. HandleEndJoinError(); 
  63.  
  64. /// <summary> 
  65. /// 錯誤提示 
  66. /// </summary> 
  67. private void HandleEndJoinError() 
  68. if (wfDlg.InvokeRequired) 
  69. wfDlg.Invoke(new HandleErrorDelegate(HandleEndJoinError)); 
  70. else 
  71. wfDlg.ShowError("無法連接聊天室!"); 
  72. ExitChatSession(); 
  73. /// <summary> 
  74. /// 登錄結束后的處理 
  75. /// </summary> 
  76. /// <param name="list"></param> 
  77. private void HandleEndJoin(string[] list) 
  78. if (wfDlg.InvokeRequired) 
  79. wfDlg.Invoke(new HandleDelegate(HandleEndJoin), new object[] { list }); 
  80. else 
  81. wfDlg.Visible = false
  82. ShowInterChatMenuItem(false); 
  83. foreach (string name in list) 
  84. lbOnlineUsers.Items.Add(name); 
  85. AppendText(" 用戶: " + userName + "--------登錄---------" + DateTime.Now.ToString()+ Environment.NewLine); 
  86. /// <summary> 
  87. /// 退出聊天室 
  88. /// </summary> 
  89. private void OutInterChatMenuItem_Click(object sender, EventArgs e) 
  90. ExitChatSession(); 
  91. Application.Exit(); 
  92. /// <summary> 
  93. /// 群聊 
  94. /// </summary> 
  95. private void btnChat_Click(object sender, EventArgs e) 
  96. SayAndClear("", txtChatContent.Text, false); 
  97. txtChatContent.Focus(); 
  98. /// <summary> 
  99. /// 發送消息 
  100. /// </summary> 
  101. private void SayAndClear(string to, string msg, bool pvt) 
  102. if (msg != ""
  103. try 
  104. CommunicationState cs = proxy.State; 
  105. //pvt 公聊還是私聊 
  106. if (!pvt) 
  107. proxy.Say(msg); 
  108. else 
  109. proxy.Whisper(to, msg); 
  110.  
  111. txtChatContent.Text = ""
  112. catch 
  113. AbortProxyAndUpdateUI(); 
  114. AppendText("失去連接: " + DateTime.Now.ToString() + Environment.NewLine); 
  115. ExitChatSession(); 
  116. private void txtChatContent_KeyPress(object sender, KeyPressEventArgs e) 
  117. if (e.KeyChar == 13) 
  118. e.Handled = true
  119. btnChat.PerformClick(); 
  120. /// <summary> 
  121. /// 只有選擇一個用戶時,私聊按鈕才可用 
  122. /// </summary> 
  123. private void lbOnlineUsers_SelectedIndexChanged(object sender, EventArgs e) 
  124. AdjustWhisperButton(); 
  125. /// <summary> 
  126. /// 私聊 
  127. /// </summary>  
  128. private void btnWhisper_Click(object sender, EventArgs e) 
  129. if (txtChatDetails.Text == ""
  130. return
  131. object to = lbOnlineUsers.SelectedItem; 
  132. if (to != null
  133. string receiverName = (string)to; 
  134. AppendText("私下對" + receiverName + "說: " + txtChatContent.Text);//+ Environment.NewLine 
  135. SayAndClear(receiverName, txtChatContent.Text, true); 
  136. txtChatContent.Focus(); 
  137. /// <summary> 
  138. /// 連接聊天室 
  139. /// </summary> 
  140. private void ShowInterChatMenuItem(bool show) 
  141. InterChatMenuItem.Enabled = show; 
  142. OutInterChatMenuItem.Enabled = this.btnChat.Enabled = !show; 
  143. private void AppendText(string text) 
  144. txtChatDetails.Text += text; 
  145. SendMessage(txtChatDetails.Handle, WM_VSCROLL, SB_BOTTOM, new IntPtr(0)); 
  146. /// <summary> 
  147. /// 退出應用程序時,釋放使用資源 
  148. /// </summary> 
  149. private void ExitChatSession() 
  150. try 
  151. proxy.Leave(); 
  152. catch { } 
  153. finally 
  154. AbortProxyAndUpdateUI(); 
  155. /// <summary> 
  156. /// 釋放使用資源 
  157. /// </summary> 
  158. private void AbortProxyAndUpdateUI() 
  159. if (proxy != null
  160. proxy.Abort(); 
  161. proxy.Close(); 
  162. proxy = null
  163. ShowInterChatMenuItem(true); 
  164. /// <summary> 
  165. /// 接收消息 
  166. /// </summary> 
  167. public void Receive(string senderName, string message) 
  168. AppendText(senderName + "說: " + message + Environment.NewLine); 
  169. /// <summary> 
  170. /// 接收私聊消息 
  171. /// </summary> 
  172. public void ReceiveWhisper(string senderName, string message) 
  173. AppendText(senderName + " 私下說: " + message + Environment.NewLine); 
  174. /// <summary> 
  175. /// 新用戶登錄 
  176. /// </summary> 
  177. public void UserEnter(string name) 
  178. AppendText("用戶 " + name + " --------登錄---------" + DateTime.Now.ToString() + Environment.NewLine); 
  179. lbOnlineUsers.Items.Add(name); 
  180. /// <summary> 
  181. /// 用戶離開 
  182. /// </summary> 
  183. public void UserLeave(string name) 
  184. AppendText("用戶 " + name + " --------離開---------" + DateTime.Now.ToString() + Environment.NewLine); 
  185. lbOnlineUsers.Items.Remove(name); 
  186. AdjustWhisperButton(); 
  187. /// <summary> 
  188. /// 控制私聊按鈕的可用性,只有選擇了用戶時按鈕才可用 
  189. /// </summary> 
  190. private void AdjustWhisperButton() 
  191. if (lbOnlineUsers.SelectedIndex == lastSelectedIndex) 
  192. lbOnlineUsers.SelectedIndex = -1; 
  193. lastSelectedIndex = -1; 
  194. btnWhisper.Enabled = false
  195. else 
  196. btnWhisper.Enabled = true
  197. lastSelectedIndex = lbOnlineUsers.SelectedIndex; 
  198.  
  199. txtChatContent.Focus(); 
  200. /// <summary> 
  201. /// 窗體關閉時,釋放使用資源 
  202. /// </summary> 
  203. private void ChatForm_FormClosed(object sender, FormClosedEventArgs e) 
  204. AbortProxyAndUpdateUI(); 
  205. Application.Exit(); 

代碼中我做了詳細的講解,相信園友們完全可以看懂。代碼中的一些使用的方法還是值得大家參考學習的。這里涉及到了WCF的使用方法,需要注意的是:如果想利用工具生成代理類,需要加上下面的代碼:

 

 
  1. if (host.Description.Behaviors.Find<System.ServiceModel.Description.ServiceMetadataBehavior>() == null
  2. BindingElement metaElement = new TcpTransportBindingElement(); 
  3. CustomBinding metaBind = new CustomBinding(metaElement); 
  4. host.Description.Behaviors.Add(new System.ServiceModel.Description.ServiceMetadataBehavior()); 
  5. host.AddServiceEndpoint(typeof(System.ServiceModel.Description.IMetadataExchange), metaBind, "MEX"); 

否則在生成代理類的時候會報錯如下的錯誤:

分享WCF聊天程序--WCFChat實現代碼

源碼下載:

/Files/gaoweipeng/WCFChat.rar


注:相關教程知識閱讀請移步到c#教程頻道。
發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 莱芜市| 湘西| 彰化市| 汾西县| 方城县| 保德县| 赞皇县| 河北区| 江口县| 桓仁| 新建县| 黄石市| 宜兰县| 民丰县| 辰溪县| 天津市| 大港区| 新巴尔虎右旗| 晋江市| 长宁县| 鲁甸县| 大安市| 昔阳县| 宁波市| 临泉县| 汝阳县| 定陶县| 三明市| 屯留县| 永平县| 义马市| 达州市| 津南区| 东源县| 徐水县| 安徽省| 田东县| 大新县| 建始县| 怀集县| 诸暨市|