一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - C# - 分享WCF聊天程序--WCFChat實現(xiàn)代碼

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

2021-11-02 13:39C#教程網(wǎng) C#

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

無意中在一個國外的站點下到了一個利用wcf實現(xiàn)聊天的程序,作者是:nikola paljetak。研究了一下,自己做了測試和部分修改,感覺還不錯,分享給大家。
先來看下運行效果:
開啟服務(wù):
分享WCF聊天程序--WCFChat實現(xiàn)代碼
客戶端程序:
分享WCF聊天程序--WCFChat實現(xiàn)代碼
分享WCF聊天程序--WCFChat實現(xiàn)代碼
程序分為客戶端和服務(wù)器端:

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

ichatservice.cs:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
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會話。雙工協(xié)定時的回調(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啟動session會話,isterminating = false 設(shè)置服務(wù)器發(fā)送回復后不關(guān)閉會話
    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>
  /// 定義一個本例的事件消息類. 創(chuàng)建包含有關(guān)事件的其他有用的信息的變量,只要派生自eventargs即可。
  /// </summary>
  public class chateventargs : eventargs
  {
    public messagetype msgtype;
    public string name;
    public string message;
  }
}

chatservice.cs

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
using system;
using system.collections.generic;
using system.linq;
using system.runtime.serialization;
using system.servicemodel;
using system.text;
 
namespace wcfchatservice
{
  // instancecontextmode.persession 服務(wù)器為每個客戶會話創(chuàng)建一個新的上下文對象。concurrencymode.multiple 異步的多線程實例
  [servicebehavior(instancecontextmode = instancecontextmode.persession, concurrencymode = concurrencymode.multiple)]
  public class chatservice : ichatservice
  {
    private static object syncobj = new object();////定義一個靜態(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)建一個靜態(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)//線程的同步性,同步訪問多個線程的任何變量,利用lock(獨占鎖),確保數(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>();//獲取當前操作客戶端實例的通道給ichatcallback接口的實例callback,此通道是一個定義為ichatcallback類型的泛類型,通道的類型是事先服務(wù)契約協(xié)定好的雙工機制。
        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);//將字典中記錄的用戶信息復制到數(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)建一個臨時委托實例
        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ù)客戶端動作通知對應(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;
      }
    }
  }
}

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
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ā)送到一個或多個窗口。此函數(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);
    //當一個窗口標準垂直滾動條產(chǎn)生一個滾動事件時發(fā)送此消息給那個窗口,也發(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);//為實現(xiàn)服務(wù)實例的對象進行初始化
      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>
    /// 登錄結(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>
    /// 只有選擇一個用戶時,私聊按鈕才可用
    /// </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)用程序時,釋放使用資源
    /// </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>
    /// 窗體關(guān)閉時,釋放使用資源
    /// </summary>
    private void chatform_formclosed(object sender, formclosedeventargs e)
    {
      abortproxyandupdateui();
      application.exit();
    }
  }
}

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

?
1
2
3
4
5
6
7
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");
      }

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

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

源碼下載:
/files/gaoweipeng/wcfchat.rar

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: www.国产一区二区三区 | 日韩精品中文字幕视频一区 | 99精品国产成人一区二区 | 欧美色图亚洲 | 美女扒开屁股 | 精品国产精品国产偷麻豆 | 牛牛影院成人免费网页 | 久久久影院亚洲精品 | 欧美成人二区 | 国产91精选学生在线观看 | 男女车车好快的车车免费网站 | 亚洲黄色大片 | 国产免费资源高清小视频在线观看 | 亚洲精品一区在线观看 | 美女任你模 | 果冻传媒在线免费观看 | 男人的天堂在线 | 俄罗斯妈妈235 | 四虎影视免费观看免费观看 | www.俺去| 日本三级s级在线播放 | 99久久精品无码一区二区毛片 | 91成人啪国产啪永久地址 | 99在线精品日韩一区免费国产 | tobu8中国在线观看免费视频 | 精品视频在线免费看 | 精品国产免费观看一区高清 | 亚洲毛片网 | 4p高h三男一女 | 久久热在线视频精品1 | 亚洲品质自拍网站 | 日本高清中文字幕一区二区三区 | 久久精品中文闷骚内射 | 精品淑女少妇AV久久免费 | 午夜国产福利视频一区 | 久热人人综合人人九九精品视频 | 无码观看AAAAAAAA片 | 成年人免费在线看的惊悚动作片 | 亚洲国产成人久久综合区 | 亚洲精品乱码久久久久久蜜桃欧美 | 国产欧美又粗又猛又爽老 |