博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
新手上路_WCF实现局域网聊天室
阅读量:5044 次
发布时间:2019-06-12

本文共 4854 字,大约阅读时间需要 16 分钟。

    利用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呢?可以看下这篇文章:

     我的理解,如果不设置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

你可能感兴趣的文章
云计算之路-阿里云上:“黑色30秒”走了,“黑色1秒”来了,真相也许大白了...
查看>>
APScheduler调度器
查看>>
设计模式——原型模式
查看>>
【jQuery UI 1.8 The User Interface Library for jQuery】.学习笔记.1.CSS框架和其他功能
查看>>
如何一个pdf文件拆分为若干个pdf文件
查看>>
web.xml中listener、 filter、servlet 加载顺序及其详解
查看>>
前端chrome浏览器调试总结
查看>>
获取手机验证码修改
查看>>
数据库连接
查看>>
python中数据的变量和字符串的常用使用方法
查看>>
等价类划分进阶篇
查看>>
delphi.指针.PChar
查看>>
Objective - C基础: 第四天 - 10.SEL类型的基本认识
查看>>
java 字符串转json,json转对象等等...
查看>>
极客前端部分题目收集【索引】
查看>>
第四天 selenium的安装及使用
查看>>
关于js的设计模式(简单工厂模式,构造函数模式,原型模式,混合模式,动态模式)...
查看>>
KMPnext数组循环节理解 HDU1358
查看>>
android调试debug快捷键
查看>>
【读书笔记】《HTTP权威指南》:Web Hosting
查看>>