利用WCF双工模式实现即时通讯

概述 

WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯。这只是个Demo,没有考虑异常处理和性能问题。解决方案结构如下:

契约

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace Service.Interface
{
 [ServiceContract(CallbackContract = typeof(ICallBack))]
 public interface INoticeOperator
 {
 [OperationContract]
 void Register(String id);

 [OperationContract]
 void UnRegister(String id);

 [OperationContract]
 void SendMessage(String from, String to, String message);
 }
}

该接口定义了三个行为,分别是:

•注册
 •注销
 •发消息

其中,在特性[ServiceContract(CallbackContract = typeof(ICallBack))]中指定了用于服务端回调客户方法的契约ICallBack,其定义如下:

 using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace Service.Interface
{
 public interface ICallBack
 {
 [OperationContract(IsOneWay = true)]
 void Notice(String message);
 }
}

实体 

本Demo只有一个实体,用来表示已经注册用户的Id和对应的回调契约的具体实现的实例:

using Service.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Models
{
 public class Client
 {
 public String Id { get; set; }

 public ICallBack CallBack { get; set; }
 }
}

契约的实现代码

 using Models;
using Service.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace Service
{
 public class NoticeOperator : INoticeOperator
 {
 private static List<Client> clientList = new List<Client>();

 public void Register(string id)
 {
  Console.WriteLine("register:" + id);

  ICallBack callBack = OperationContext.Current.GetCallbackChannel<ICallBack>();
  clientList.Add(new Client() { Id = id, CallBack = callBack });
 }

 public void UnRegister(string id)
 {
  Console.WriteLine("unRegister:" + id);

  Client client = clientList.Find(c => c.Id == id);
  if (client != null)
  {
  clientList.Remove(client);
  }
 }

 public void SendMessage(string from, string to, string message)
 {
  Client client = clientList.Find(c => c.Id == to);
  if (client != null)
  {
  String longMessage = String.Format("message from {0} to {1} at {2} : {3}", from, to, DateTime.Now.ToString("HH:mm:ss"), message);
  Console.WriteLine(longMessage);
  client.CallBack.Notice(longMessage);
  }
 }
 }
}

Register方法用来把Client实体加入到一个列表中,模拟注册行为,Clinet实体包含了用户信息和实现了回调契约的一个实例对象。

UnRegister方法用来把一个Client从列表中移除,模拟注销行为。

SendMessage方法用来发送消息,第一个参数是发送者的Id,第二个参数是消息接受者的Id,第三个参数是发送内容,该方法先将消息在服务端打印出来,然后再回调消息接收者对应的回调契约的具体实现类的实例对象的Notice方法以达到服务端向客户端发送消息的目的。

宿主

using Service;
using Service.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Text;
using System.Threading.Tasks;

namespace Hosting
{
 class Program
 {
 static void Main(string[] args)
 {
  using (ServiceHost host = new ServiceHost(typeof(NoticeOperator)))
  {
  host.AddServiceEndpoint(typeof(INoticeOperator), new NetTcpBinding(), "net.tcp://127.0.0.1:9527/NoticeOperator");

  host.Opened += (s, e) => Console.WriteLine("service is running...");
  host.Open();
  Console.ReadLine();
  }
 }
 }
}

宿主是一个控制台应用程序,使用的绑定类型为NetTcpBinding,端口是华安的华府的终生代号。

客户端代码

实现回调接口

using Service.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
 class CallBack : ICallBack
 {
 public void Notice(string message)
 {
  Console.WriteLine(message);
 }
 }
}

模拟注册,发消息和注销

 using Service.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Threading.Tasks;

namespace Test
{
 class Program
 {
 static void Main(string[] args)
 {
  InstanceContext context = new InstanceContext(new CallBack());
  using (ChannelFactory<INoticeOperator> factory = new DuplexChannelFactory<INoticeOperator>(context, new NetTcpBinding(), "net.tcp://127.0.0.1:9527/NoticeOperator"))
  {
  INoticeOperator proxy = factory.CreateChannel();

  String selfId = args[0];
  String friendId = args[1];

  proxy.Register(selfId);
  Console.WriteLine("----------Register------------");

  while(true)
  {
   String message = Console.ReadLine();
   if (message == "q")
   {
   proxy.UnRegister(selfId);
   break;
   }
   else
   {
   proxy.SendMessage(selfId, friendId, message);
   }
  }
  }
 }
 }
}

在CMD中运行test.exe Joey Ross表示Joey注册,要给他的朋友Ross发送消息;再起一个进程test.exe Ross Joey表示Ross注册,要给他的朋友Joey发送消息。进程启动后输入一些字符按回车即发送至了对方,输入q回车注销并退出程序。如下图所示:

Ross:

Joey:

服务端:

参考资料

•无废话WCF入门教程五[WCF的通信模式]
 •同事 @麦枫 的代码
 •《WCF全面解析》

后记

这仅仅是个Demo,在实际项目中如果同时在线人数非常多,这样做的性能是否可行还需进一步对WCF双工模式的工作方式进行深入学习。

解决方案下载地址:WCFDemo

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • 利用WCF双工模式实现即时通讯

    概述  WCF陆陆续续也用过多次,但每次都是浅尝辄止,以将够解决问题为王道,这几天稍闲,特寻了些资料看,昨晚尝试使用WCF的双工模式实现了一个简单的即时通讯程序,通过服务端转发实现客户端之间的通讯.这只是个Demo,没有考虑异常处理和性能问题.解决方案结构如下: 契约 using System; using System.Collections.Generic; using System.Linq; using System.ServiceModel; using System.Text; us

  • vue中利用mqtt服务端实现即时通讯的步骤记录

    MQTT协议 MQTT(Message Queuing Telemetry Transport,消息队列遥测传输)是IBM开发的一个即时通讯协议,有可能成为物联网的重要组成部分.该协议支持所有平台,几乎可以把所有联网物品和外部连接起来,被用来当做传感器和制动器(比如通过Twitter让房屋联网)的通信协议. MQTT是轻量级基于代理的发布/订阅的消息传输协议,它可以通过很少的代码和带宽和远程设备连接.例如通过卫星和代理连接,通过拨号和医疗保健提供者连接,以及在一些自动化或小型设备上,而且由于小巧

  • Android Socket接口实现即时通讯实例代码

    Android Socket接口实现即时通讯 最近学习Android 通信的知识,做一个小实例,巩固下学习内容,以下内容是网上找的资料,觉得很不错,知识比较全面,大家看下. 首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.

  • 详解android环境下的即时通讯

    首先了解一下即时通信的概念.通过消息通道 传输消息对象,一个账号发往另外一账号,只要账号在线,可以即时获取到消息,这就是最简单的即使通讯.消息通道可由TCP/IP UDP实现.通俗讲就是把一个人要发送给另外一个人的消息对象(文字,音视频,文件)通过消息通道(C/S实时通信)进行传输的服务.即时通讯应该包括四种形式,在线直传.在线代理.离线代理.离线扩展.在线直传指不经过服务器,直接实现点对点传输.在线代理指消息经过服务器,在服务器实现中转,最后到达目标账号.离线代理指消息经过服务器中转到达目标账

  • 如何利用微信小程序和php实现即时通讯聊天功能

    目录 一.PHP7安装Swoole扩展 1.自定义安装 2.宝塔面板安装PHP swoole扩展 二.配置nginx反向代理 三.微信小程序socket合法域名配置 四.效果演示和代码 1.小程序端代码 2.服务端代码(PHP代码) 五.代码已经编写完了 总结 一.PHP7安装Swoole扩展 PHP swoole 扩展下载地址 Github:https://github.com/swoole/swoole-src/tags php官方扩展库:http://pecl.php.net/packag

  • Android Easeui 3.0 即时通讯的问题汇总

    0.关于注册账号就不用说了. 1.创建应用.获取appkey 0.创建应用 1.填写信息 2.获取appkey 2.集成 0.首先新建一个工程 1.这里主要介绍使用easeui来集成环信的即时通讯功能,需要下载sdk 2.把easeui当做依赖导入到工程当中,然后建立依赖关系 3在导入之后可能会出现的问题: 3.0 <uses-permission android:name="android.permission.ACCESS_MOCK_LACATTON> 这个权限报错,在咨询官方技

  • Python基于socket实现简单的即时通讯功能示例

    本文实例讲述了Python基于socket实现简单的即时通讯功能.分享给大家供大家参考,具体如下: 客户端tcpclient.py # -*- coding: utf-8 -*- import socket import threading # 目标地址IP/URL及端口 target_host = "127.0.0.1" target_port = 9999 # 创建一个socket对象 client = socket.socket(socket.AF_INET,socket.SOC

  • 使用WebSocket实现即时通讯(一个群聊的聊天室)

    随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSocket协议被提出,它实现了浏览器与服务器的全双工通信,扩展了浏览器与服务端的通信功能,使服务端也能主动向客户端发送数据. 传统的HTTP协议是无状态的,每次请求(request)都要由客户端(如浏览器)主动发起,服务端进行处理后返回response结果,而服务端很难主动向客户端发送数据:这种客户端是主动方,服务端是被动方的传统Web模式对于信息变化不频繁的Web应用来说造成的麻烦

  • nodejs结合Socket.IO实现的即时通讯功能详解

    本文实例讲述了nodejs结合Socket.IO实现的即时通讯功能.分享给大家供大家参考,具体如下: 动态web 在html5以前,web的设计上并没有考虑过动态,他一直是围绕着文档设计的,我们看以前比较老的网站,基本上都是某一刻用来显示单一的文档的,用户请求一次web页面,获取一个页面,但是随着时间的推移,人们想要web做更多的事情了,而不是简单的要显示文档,而javaScript一直处于开发人员推动web页面功能的发展中心. Ajax无疑是动态Web页面的一个重大发展,他不再需要我们即使更新

  • 使用Android WebSocket实现即时通讯功能

    最近做这个功能,分享一下.即时通讯(Instant Messaging)最重要的毫无疑问就是即时,不能有明显的延迟,要实现IM的功能其实并不难,目前有很多第三方,比如极光的JMessage,都比较容易实现.但是如果项目有特殊要求(如不能使用外网),那就得自己做了,所以我们需要使用WebSocket. WebSocket WebSocket协议就不细讲了,感兴趣的可以具体查阅资料,简而言之,它就是一个可以建立长连接的全双工(full-duplex)通信协议,允许服务器端主动发送信息给客户端. Ja

随机推荐