新手上路_WCF实现局域网聊天室

    利用WCF实现一个局域网的聊天室,是一件很简单的事情。不过还是需要稍微了解一下WCF的基本知识,并最好能够写几个小程序试试。推荐Artech的WCF系列。

    首先说一个我的实现思路,设A为服务,B1,B2,B3为三个客户端。B1发送消息到A,然后A把消息转发给B1,B2,B3,这样聊天室就基本差不多了。用到的WCF绑定肯定是支持回调的,我用的是WsDualHttpBinding。

    下面是Service的契约代码:  

 
  
1 using System;
2   using System.Collections.Generic;
3   using System.Linq;
4 using System.Text;
5 using System.ServiceModel;
6
7 namespace CTalk2_0_Service
8 {
9 [ServiceContract(CallbackContract = typeof (IServiceContractCallback))]
10 interface IServiceContract
11 {
12 [OperationContract(IsOneWay = true )]
13 void Connect();
14 [OperationContract(IsOneWay = true )]
15 void DisConnect();
16 [OperationContract(IsOneWay = true )]
17 void ShowOnLineUsers(UserInfo userinfo, bool flag);
18 [OperationContract(IsOneWay = true )]
19 void ShowMessage(Message message);
20 }
21
22 interface IServiceContractCallback
23 {
24 [OperationContract(IsOneWay = true )]
25 void UpdateNameList(List < UserInfo > list, bool flag);
26 [OperationContract(IsOneWay = true )]
27 void UpdateMessageList(Message message);
28 }
29
30 [Serializable]
31 public class UserInfo
32 {
33 public string Name;
34 public string Sex;
35 }
36 [Serializable]
37 public class Message
38 {
39 public string Name;
40 public string Words;
41 }
42 }

     服务端有Connect和Disconnect两种方法,一个客户端连入聊天室的时候,调用Connect,把回调对象传给服务。服务端将此回调对象存下,以便将来进行操作。当客户端要退出聊天室的时候,调用DisConnect方法,这样服务端就会移去此客户端对应的回调对象,这样就可以保证回调对象的有效性。

     至于为什么方法都是OneWay = true呢?可以看下这篇文章:http://www.cnblogs.com/artech/archive/2007/03/29/692032.html

     我的理解,如果不设置OneWay,那么就是Request/Response的模式,意味着,一旦Client发出请求,就阻塞自己,获得了Server的回应后,才继续运行。引入了回调,就变得更加复杂。主要就是线程死锁的问题。

     下面是Service的实现代码:

  

ContractedBlock.gif ExpandedBlockStart.gif View Code
 
   
1 [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, InstanceContextMode = InstanceContextMode.PerCall)]
2 public class MyService : IServiceContract
3 {
4 static List < IServiceContractCallback > list = new List < IServiceContractCallback > ();
5 static List < UserInfo > userList = new List < UserInfo > ();
6
7 public void Connect()
8 {
9 IServiceContractCallback callback = OperationContext.Current.GetCallbackChannel < IServiceContractCallback > ();
10 if (list.Contains(callback) == false )
11 {
12 list.Add(callback);
13 }
14 Console.WriteLine( " 当前在线用户数: " + list.Count());
15 }
16
17 public void DisConnect()
18 {
19 IServiceContractCallback callback = OperationContext.Current.GetCallbackChannel < IServiceContractCallback > ();
20 if (list.Contains(callback) == true )
21 {
22 list.Remove(callback);
23 }
24 Console.WriteLine( " 当前在线用户数: " + list.Count());
25 }
26
27 public void ShowOnLineUsers(UserInfo userinfo, bool flag)
28 {
29 if (flag == true )
30 {
31 Func < UserInfo, bool > function1 = delegate (UserInfo user)
32 {
33 if (user.Name == userinfo.Name && user.Sex == userinfo.Sex) return false ;
34 else return true ;
35 };
36 if (userList.All < UserInfo > (function1) == true ) userList.Add(userinfo);
37 }
38 else
39 {
40 Func < UserInfo, bool > function2 = delegate (UserInfo user)
41 {
42 if (user.Name == userinfo.Name && user.Sex == userinfo.Sex) return true ;
43 else return false ;
44 };
45 if (userList.Any < UserInfo > (function2) == true )
46 {
47 foreach (UserInfo element in userList)
48 {
49 if (element.Name == userinfo.Name && element.Sex == userinfo.Sex) element.Name = " RemoveFlag " ;
50 }
51 }
52 }
53 if (userList.Count == 0 ) userList.Add(userinfo);
54 List < UserInfo > userList1 = new List < UserInfo > ();
55 foreach (UserInfo element in userList)
56 {
57 if (element.Name != " RemoveFlag " ) userList1.Add(element);
58 }
59 Action < IServiceContractCallback > method = delegate (IServiceContractCallback callback)
60 {
61 if (callback != null )
62 {
63 callback.UpdateNameList(userList1, flag);
64 }
65 };
66 list.ForEach(method);
67 }
68
69 public void ShowMessage(Message message)
70 {
71 Action < IServiceContractCallback > method = delegate (IServiceContractCallback callback)
72 {
73 if (callback != null )
74 {
75 callback.UpdateMessageList(message);
76 }
77 };
78 list.ForEach(method);
79 }
80 }

    客户端如果是Winform写的话,还有个问题需要注意,就是怎样去用客户端的服务线程去更新Winform控件的内容。Winform的控件是不能被其他线程随意更改的,因此要刷新Winform控件的内容,可以使用下面的实现方式:

 

 
  
1 public void BindListBox(UserInfo[] list, bool flag)
2 {
3 UpdateControlDelegate bindListBox = delegate (UserInfo[] list1, bool flag1)
4 {
5 List < string > listString = new List < string > ();
6 foreach (UserInfo element in list1)
7 {
8 listString.Add(element.Name + " " + element.Sex);
9 }
10 this .UserList.DataSource = listString;
11 this .UserList.Show();
12 };
13 this .Invoke(bindListBox, list, flag);
14 }
15
16 public void UpdateChatLog( string text)
17 {
18 UpdateChatLogDelegate updataChatLog = delegate ( string text1)
19 {
20 this .ChatLog.Text += text1;
21 };
22 this .Invoke(updataChatLog, text);
23 }
24 private delegate void UpdateControlDelegate(UserInfo[] list, bool flag);
25 private delegate void UpdateChatLogDelegate( string text);

 下面是截图:

2011031421102147.png

2011031421110242.png

转载于:https://www.cnblogs.com/anthony_Suger/archive/2011/03/14/1984192.html

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值