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

首頁 > 編程 > C# > 正文

分享WCF聊天程序--WCFChat實(shí)現(xiàn)代碼

2020-01-24 01:23:47
字體:
供稿:網(wǎng)友

無意中在一個(gè)國外的站點(diǎn)下到了一個(gè)利用WCF實(shí)現(xiàn)聊天的程序,作者是:Nikola Paljetak。研究了一下,自己做了測試和部分修改,感覺還不錯(cuò),分享給大家。
先來看下運(yùn)行效果:
開啟服務(wù):

客戶端程序:


程序分為客戶端和服務(wù)器端:

------------服務(wù)器端:

IChatService.cs:

using 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會(huì)話。雙工協(xié)定時(shí)的回調(diào)協(xié)定類型為IChatCallback接口  [ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IChatCallback))]  public interface IChatService  {    [OperationContract(IsOneWay = false, IsInitiating = true, IsTerminating = false)]//----->IsOneWay = false等待服務(wù)器完成對方法處理;IsInitiating = true啟動(dòng)Session會(huì)話,IsTerminating = false 設(shè)置服務(wù)器發(fā)送回復(fù)后不關(guān)閉會(huì)話    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>  /// 雙向通信的回調(diào)接口  /// </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>  /// 設(shè)定消息的類型  /// </summary>  public enum MessageType { Receive, UserEnter, UserLeave, ReceiveWhisper };  /// <summary>  /// 定義一個(gè)本例的事件消息類. 創(chuàng)建包含有關(guān)事件的其他有用的信息的變量,只要派生自EventArgs即可。  /// </summary>  public class ChatEventArgs : EventArgs  {    public MessageType msgType;    public string name;    public string message;  }}

ChatService.cs

using System;using System.Collections.Generic;using System.Linq;using System.Runtime.Serialization;using System.ServiceModel;using System.Text;namespace WCFChatService{  // InstanceContextMode.PerSession 服務(wù)器為每個(gè)客戶會(huì)話創(chuàng)建一個(gè)新的上下文對象。ConcurrencyMode.Multiple 異步的多線程實(shí)例  [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Multiple)]  public class ChatService : IChatService  {    private static Object syncObj = new Object();////定義一個(gè)靜態(tài)對象用于線程部份代碼塊的鎖定,用于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>();//創(chuàng)建一個(gè)靜態(tài)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方法作為參數(shù)傳遞給委托      lock (syncObj)//線程的同步性,同步訪問多個(gè)線程的任何變量,利用lock(獨(dú)占鎖),確保數(shù)據(jù)訪問的唯一性。      {        if (!chatters.ContainsKey(name) && name != "" && name != null)        {          this.name = name;          chatters.Add(name, MyEventHandler);          userAdded = true;        }      }      if (userAdded)      {        callback = OperationContext.Current.GetCallbackChannel<IChatCallback>();//獲取當(dāng)前操作客戶端實(shí)例的通道給IChatCallback接口的實(shí)例callback,此通道是一個(gè)定義為IChatCallback類型的泛類型,通道的類型是事先服務(wù)契約協(xié)定好的雙工機(jī)制。        ChatEventArgs e = new ChatEventArgs();//實(shí)例化事件消息類ChatEventArgs        e.msgType = MessageType.UserEnter;        e.name = name;        BroadcastMessage(e);        ChatEvent += myEventHandler;        string[] list = new string[chatters.Count]; //以下代碼返回當(dāng)前進(jìn)入聊天室成員的稱列表        lock (syncObj)        {          chatters.Keys.CopyTo(list, 0);//將字典中記錄的用戶信息復(fù)制到數(shù)組中返回。        }        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;//創(chuàng)建一個(gè)臨時(shí)委托實(shí)例        lock (syncObj)        {          chatterTo = chatters[to]; //查找成員字典中,找到要接收者的委托調(diào)用        }        chatterTo.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);//異步方式調(diào)用接收者的委托調(diào)用      }      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);    }    //回調(diào),根據(jù)客戶端動(dòng)作通知對應(yīng)客戶端執(zhí)行對應(yīng)的操作    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)      {        //循環(huán)將在線的用戶廣播信息        foreach (ChatEventHandler handler in temp.GetInvocationList())        {          //異步方式調(diào)用多路廣播委托的調(diào)用列表中的ChatEventHandler           handler.BeginInvoke(this, e, new AsyncCallback(EndAsync), null);        }      }    }    //廣播中線程調(diào)用完成的回調(diào)方法功能:清除異常多路廣播委托的調(diào)用列表中異常對象(空對象)    private void EndAsync(IAsyncResult ar)    {      ChatEventHandler d = null;      try      {        //封裝異步委托上的異步操作結(jié)果        System.Runtime.Remoting.Messaging.AsyncResult asres = (System.Runtime.Remoting.Messaging.AsyncResult)ar;        d = ((ChatEventHandler)asres.AsyncDelegate);        d.EndInvoke(ar);      }      catch      {        ChatEvent -= d;      }    }  }}

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

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.Runtime.InteropServices;using System.ServiceModel;namespace WCFChatClient{  public partial class ChatForm : Form, IChatServiceCallback  {    /// <summary>    /// 該函數(shù)將指定的消息發(fā)送到一個(gè)或多個(gè)窗口。此函數(shù)為指定的窗口調(diào)用窗口程序,直到窗口程序處理完消息再返回。     /// </summary>    /// <param name="hWnd">其窗口程序?qū)⒔邮障⒌拇翱诘木浔?lt;/param>    /// <param name="msg">指定被發(fā)送的消息</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);    //當(dāng)一個(gè)窗口標(biāo)準(zhǔn)垂直滾動(dòng)條產(chǎn)生一個(gè)滾動(dòng)事件時(shí)發(fā)送此消息給那個(gè)窗口,也發(fā)送給擁有它的控件    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>    /// 連接服務(wù)器    /// </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);//為實(shí)現(xiàn)服務(wù)實(shí)例的對象進(jìn)行初始化      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>    /// 錯(cuò)誤提示    /// </summary>    private void HandleEndJoinError()    {      if (wfDlg.InvokeRequired)        wfDlg.Invoke(new HandleErrorDelegate(HandleEndJoinError));      else      {        wfDlg.ShowError("無法連接聊天室!");        ExitChatSession();      }    }    /// <summary>    /// 登錄結(jié)束后的處理    /// </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>    /// 發(fā)送消息    /// </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>    /// 只有選擇一個(gè)用戶時(shí),私聊按鈕才可用    /// </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>    /// 退出應(yīng)用程序時(shí),釋放使用資源    /// </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>    /// 控制私聊按鈕的可用性,只有選擇了用戶時(shí)按鈕才可用    /// </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>    /// 窗體關(guān)閉時(shí),釋放使用資源    /// </summary>    private void ChatForm_FormClosed(object sender, FormClosedEventArgs e)    {      AbortProxyAndUpdateUI();      Application.Exit();    }  }}

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

if (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");      }

否則在生成代理類的時(shí)候會(huì)報(bào)錯(cuò)如下的錯(cuò)誤:

源碼下載:
/Files/gaoweipeng/WCFChat.rar

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 长武县| 肥乡县| 新郑市| 东至县| 龙南县| 张家口市| 新源县| 天镇县| 临沂市| 嘉定区| 漳州市| 临清市| 福贡县| 昌都县| 革吉县| 宜昌市| 明溪县| 张家口市| 西昌市| 巴林右旗| 贵州省| 阿勒泰市| 从化市| 客服| 抚远县| 香港| 都兰县| 林甸县| 台北市| 秦安县| 涞水县| 延寿县| 炉霍县| 神木县| 望奎县| 类乌齐县| 枣强县| 建始县| 洛南县| 扎鲁特旗| 泗阳县|