新手上路_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的实现代码:

  

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);

 下面是截图:

posted @ 2011-03-14 21:12  来日方糖  阅读(1845)  评论(17编辑  收藏  举报