WCF双工通信研究之与silverlight借助tcp协议通信
本文测试环境:
wcf宿主在控制台上
silverlight和wcf之间的通信使用tcp协议
定义契约
依然使用上一篇的例子,我们需要另外定义一个契约及其实现
服务契约:
[ServiceContract(CallbackContract=typeof(IChatClient))] public interface IChatService { [OperationContract] void SendMessage(WCFModel.Message message); } [ServiceContract] public interface IChatClient { [OperationContract(IsOneWay=true)] void GetMessage(WCFModel.Message message); }
数据契约:
[DataContract] public class Message { [DataMember] public string To { get; set; } [DataMember] public string From { get; set; } [DataMember] public string Content { get; set; } }
实现契约
这里的实现使用一个集合存储了所有连接客户端的回调句柄及每个客户端的标识,用一个类来存放
public class ClientHandler { public string Name { set; get; } public IChatClient Client { set; get; } }
下面是实现的具体代码,基本逻辑为只要有用户发送消息到服务端,遍历整个客户端集合,触发回调句柄将消息发送出去,并删除消息。
public class ChatService:IChatService { static List<WCFModel.Message> ListOfMessages = new List<WCFModel.Message>(); IChatClient client; static List<ClientHandler> ListOfClient = new List<ClientHandler>(); public void SendMessage(WCFModel.Message message) { ListOfMessages.Add(message); client = OperationContext.Current.GetCallbackChannel<IChatClient>(); if(ListOfClient.Where(m=>m.Name==message.From).Count()==0) { ListOfClient.Add(new ClientHandler() { Name=message.From, Client=client }); } foreach(var item in ListOfClient) { if (ListOfMessages.Where(m => m.To == item.Name).Count() > 0) { var msg = ListOfMessages.Where(m => m.To == item.Name).FirstOrDefault(); item.Client.GetMessage(msg); ListOfMessages.RemoveAll(m=>m.To==item.Name); } } } }
服务寄宿
然后将此服务寄宿到控制台
class Program { static void Main(string[] args) { MyHost.Open(); System.Console.WriteLine("服务已经启动... 敲回车键停止服务"); System.Console.ReadLine(); MyHost.Close(); } } public class MyHost { static ServiceHost host = null; public static void Open() { host = new ServiceHost(typeof(WCFLibrary.ChatService)); host.Open(); } } 配置文件
<service behaviorConfiguration="WCFLibrary.UpdateUserBehavior" name="WCFLibrary.ChatService"> <host> <baseAddresses> <add baseAddress="net.tcp://localhost:4506/ChatService"/> </baseAddresses> </host> <endpoint address="" binding="netTcpBinding" contract="WCFLibrary.IChatService" bindingConfiguration="netTcpBindConfig"></endpoint> <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" ></endpoint> </service>
客户端访问
silverlight作为客户端先引用服务以便自动生成客户端代理
然后编写代码来访问服务
public partial class MainPage : UserControl { ChatService.ChatServiceClient proxy; public MainPage() { InitializeComponent(); } private void txtSend_Click(object sender, RoutedEventArgs e) { proxy = new ChatService.ChatServiceClient(); proxy.GetMessageReceived += (obj, arg) => { if (arg.Error == null) { this.txtChatArea.Text += arg.message.Content + Environment.NewLine; } }; proxy.SendMessageCompleted += (obj, arg) => { if (arg.Error == null) { this.txtChatArea.Text += "发¢送í成é功|!?" + Environment.NewLine; } }; proxy.SendMessageAsync(new ChatService.Message() { From=this.txtFrom.Text, To=this.txtTo.Text, Content=this.txtContent.Text }); } }
整体的运行结果
注意事项
本文最重要的地方,在于客户端请求服务器后,在服务器端保存了客户端的回调句柄,在需要的时候进行回调。
static List<ClientHandler> ListOfClient = new List<ClientHandler>();
client = OperationContext.Current.GetCallbackChannel<IChatClient>(); if(ListOfClient.Where(m=>m.Name==message.From).Count()==0) { ListOfClient.Add(new ClientHandler() { Name=message.From, Client=client }); }
而在客户端呢,需要绑定这个回调事件
proxy = new ChatService.ChatServiceClient(); proxy.GetMessageReceived += (obj, arg) => { if (arg.Error == null) { this.txtChatArea.Text += arg.message.Content + Environment.NewLine; } };
源代码:https://files.cnblogs.com/wengyuli/WCFTCPConsoleDuplex.rar