坦白讲,我们公司其实没啥技术实力,之所以还能不断接到各种项目,全凭我们老板神通广大!要知道他每次的饭局上可都是些什么人物!

但是项目接下一大把,就凭咱哥儿几个的水平,想要独立自主、保质保量保期地一个个做出来,那也是有点难以置信。之前咱也跟老板反映过这个困难,建议他再召两个高手过来。不过领导虽然书读的不多,有一句古训倒是背得特别熟——“君子生非异也,善假于物也”。所以咱们公司一直奉行拿来主义。

园子里的这个GGTalk,咱们前前后后用它移花接木做的IM项目也不下三四个了。初次入手的时候,洋洋代码,多少感觉有些难以把握。不过一来二去,理清了头绪,也就一览无余了。

相信跟我们一样想要利用GGTalk的同学大有人在,于是我打算写这样一个《GGTalk源码详解系列》,把自己对GGTalk的梳理分享给大家,让大家更容易上手。

那接下来我们就言归正传。

一.GGTalk的宏观结构

如图,GGTalk中有4个项目,第一个“GGTalk”是客户端项目;“GGTalk.Core”是客户端和服务端共用的一些类,主要包括一些数据实体,还有一些通信协议类;“GGTalk.Server”是服务端项目;“JustLib”是作者封装的一些常用类和控件。

二.GGTalk是如何实现注册的?

GGTalk采用Remoting技术来完成注册。

1.先定义接口

namespace GGTalk
{
    /// <summary>
    /// 用于提供注册服务的Remoting接口。
    /// </summary>
    public interface IRemotingService :IChatRecordPersister
    {
        RegisterResult Register(GGUser user); 

        /// <summary>
        /// 根据ID或Name搜索用户【完全匹配】。
        /// </summary>
        List<GGUser> SearchUser(string idOrName);

        /// <summary>
        /// 发送系统通知给所有在线用户。
        /// </summary>
        void SendSystemNotify(string title, string content);
    }
}

2.服务端接口实现

namespace GGTalk.Server
{
    internal class RemotingService :MarshalByRefObject, IRemotingService
    {
        private GlobalCache globalCache;
        private IRapidServerEngine rapidServerEngine;
        public RemotingService(GlobalCache db ,IRapidServerEngine engine)
        {
            this.globalCache = db;
            this.rapidServerEngine = engine;
        }     public RegisterResult Register(GGUser user)
        {
            try
            {
                if (this.globalCache.IsUserExist(user.UserID))
                {
                    return RegisterResult.Existed;
                }
                this.globalCache.InsertUser(user);
                return RegisterResult.Succeed;
            }
            catch (Exception ee)
            {
                return RegisterResult.Error;
            }
        }

        public List<GGUser> SearchUser(string idOrName)
        {
            return this.globalCache.SearchUser(idOrName);
        }

        public override object InitializeLifetimeService()
        {
            return null;
        }
    }
}

3.服务端发布服务

 #region 发布用于注册的Remoting服务
 RemotingConfiguration.Configure("GGTalk.Server.exe.config", false);
 RemotingService registerService = new Server.RemotingService(globalCache ,Program.RapidServerEngine);
 RemotingServices.Marshal(registerService, "RemotingService");
 #endregion      

服务端配置文件:

<system.runtime.remoting>
    <application>
      <channels>
        <!--用户注册Remoting服务端口-->
        <channel ref="tcp" port="4500" >
          <serverProviders>
            <provider ref="wsdl" />
            <formatter ref="soap" typeFilterLevel="Full" />
            <formatter ref="binary" typeFilterLevel="Full" />
          </serverProviders>
          <clientProviders>
            <formatter ref="binary" />
          </clientProviders>
        </channel>
      </channels>
    </application>
  </system.runtime.remoting>

4.客户端订阅服务

int registerPort = int.Parse(ConfigurationManager.AppSettings["RemotingPort"]);
this.remotingService = (IRemotingService)Activator.GetObject(typeof(IRemotingService), string.Format("tcp://{0}:{1}/RemotingService", ConfigurationManager.AppSettings["ServerIP"], registerPort)); ;

三.总结Remoting技术

1.Remoting使用中的三要素:

1.一个可远程处理的对象。

2.一个服务端应用程序域用(也叫宿主应用程序域中),于侦听针对该对象的请求。

3.一个客户端应用程序域,用于发出针对该对象的请求。

2.代理:

代理是一个提供了和真实对象完全一样的接口、公共方法、属性等成员的对象。在运行过程中,.NET Remoting基于对象元数据生成代理。代理只提供接口,不提供对象的状态,因为对象的真正状态在宿主应用程序域中存储。代理在这里只转发调用。转发调用到一个对象叫封送处理。封送处理的目标是让客户端调用服务端时感觉不到是在与远端对象交流,而是与本地对象在交流。如果通过代理来访问对象,该对象必需是从 MarshalByRefObject抽象类派生。

3.Remoting架构:

四.知识点拓展

1. 用应用程序域

操作系统和运行库环境通常会在应用程序间提供某种形式的隔离。例如,Microsoft Windows 使用进程来隔离应用程序。为确保在一个应用程序中运行的代码不会对其他不相关的应用程序产生不良影响,这种隔离是必需的。

2.用应用程序域优点

在一个应用程序中出现的错误不会影响其他应用程序。因为类型安全的代码不会导致内存错误,所以使用应用程序域可以确保在一个域中运行的代码不会影响进程中的其他应用程序。

能够在不停止整个进程的情况下停止单个应用程序。使用应用程序域使您可以卸载在单个应用程序中运行的代码。

在一个应用程序中运行的代码不能直接访问其他应用程序中的代码或资源。为了强制实施此隔离,公共语言运行库禁止在不同应用程序域中的对象之间进行直接调用。要在各域之间传递对象,可以复制这些对象,或通过代理访问这些对象。如果复制对象,那么对该对象的调用为本地调用。也就是说,调用方和被引用的对象位于同一应用程序域中。如果通过代理访问对象,那么对该对象的调用为远程调用。在此情况下,调用方和被引用的对象位于不同的应用程序域中。域间调用所采用的远程调用基础结构与两个进程间的调用或两台计算机间的调用的基础结构相同。因此,被引用的对象的元数据必须对于两个应用程序域均可用,以便用 JIT 正确编译该方法调用。如果调用域对被调用对象的元数据没有访问权,则编译可能失败,并引发类型为 System.IO.FileNotFound 的异常。

代码行为的作用范围由它运行所在的应用程序决定。换言之,应用程序域将提供应用程序版本策略等配置设置、它所访问的任意远程程序集的位置,以及加载到该域中的程序集的位置信息。

向代码授予的权限可以由代码运行所在的应用程序域来控制。

五.后记

这是该系列的第一篇,一篇博客篇幅有限,能讲清楚一两个问题已经很不错。要想把GGTalk全部讲透,恐怕得要上百篇博客才够。希望我做的工作能给大家带来收获,一方面可以方便大家利用GGTalk,另一方面也为学习GGTalk的同学提供一个参考,希望大家可以从中汲取营养,不仅仅是复用这些代码,也能够从中学到蕴含着的知识与技术。

解读GGTalk,这个工作很辛苦,希望大家鼓励,也希望更多的朋友参与其中!

套用GGTalk做项目的经验总结——GGTalk源码详解系列(一)的更多相关文章

  1. Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码)

    Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合(注解及源码) 备注: 之前在Spring3 + Spring MVC+ Mybatis 3+Mysql 项目整合中 ...

  2. [转]3天搞定的小型B/S内部管理类软件定制开发项目【软件开发实战10步骤详解】

    本文转自:http://www.cnblogs.com/jirigala/archive/2010/10/07/1845275.html 2010-10-07 21:39 by 通用C#系统架构, 5 ...

  3. 做个简单的Redis监控(源码分享)

    Redis监控 Redis 是目前应用广泛的NoSQL,我做的项目中大部分都是与Redis打交道,发现身边的朋友也更多人在用,相对于memcached 来说,它的优势也确实是可圈可点.在随着业务,数据 ...

  4. JNI_Android项目中调用.so动态库实现详解

    转自:http://www.yxkfw.com/?p=7223 1. 在Eclipse中创建项目:TestJNI 2. 新创建一个class:TestJNI.java package com.wwj. ...

  5. JNI_Android项目中调用.so动态库实现详解【转】

    转自 http://www.cnblogs.com/sevenyuan/p/4202759.html 1. 在Eclipse中创建项目:TestJNI 2. 新创建一个class:TestJNI.ja ...

  6. Mybaits+SpringMVC项目(含代码生成工具源码)

       大家下载下来修改数据库配置应该就能运行起来,里面有一个SM的简单案例了,还有说明文件. 运行效果    工具类可以生成Springmvc+mybatis的相关类和配置文件,并具有增删查改的功能, ...

  7. Extjs6(特别篇)——项目自带例子main.js拆分详解

    本文基于extjs6.0.0 一.拆分代码来看看 1.主页面main是个tab页: 写一些页面的依赖: 标明页面的controller和viewModel Ext.define('Learning.v ...

  8. 关于 Eclipse中的Web项目 部署的文件位置 查看jsp源码的部署位置

    使用 eclipse 开发web项目 会默认 部署在 工作目录下: .metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps 在这里 ...

  9. 即时通信系统中如何实现:全局系统通知,并与Web后台集成?【低调赠送:QQ高仿版GGTalk 5.1 最新源码】

    像QQ这样的即时通信软件,时不时就会从桌面的右下角弹出一个小窗口,或是显示一个广告.或是一个新闻.或是一个公告等.在这里,我们将其统称为“全局系统通知”.很多使用GGTalk的朋友都建议我加上一个类似 ...

随机推荐

  1. dpkg:处理软件包dradis (--configure)时出错

    dpkg:处理软件包dradis (--configure)时出错!解决方案:1.将info文件夹更名%mv /var/lib/dpkg/info /var/lib/dpkg/info_old2.新建 ...

  2. 基于C/S架构的3D对战网络游戏C++框架 _06搭建C/S架构的基本通信框架(尚未写完会重新编辑后再发出)

    本系列博客主要是以对战游戏为背景介绍3D对战网络游戏常用的开发技术以及C++高级编程技巧,有了这些知识,就可以开发出中小型游戏项目或3D工业仿真项目. 笔者将分为以下三个部分向大家介绍(每日更新): ...

  3. Python socket超时

    #server.py import socket s=socket.socket() s.bind(('127.0.0.1',2000)) s.listen(5) while 1: cs,addres ...

  4. border在IE6设置transparent无效

    在ie6下给border设置transparent是无效的,解决办法如下: _border-color:tomato; /*For IE6-*/ _filter:chroma(color=tomato ...

  5. 微信公众平台C# SDK:Senparc.Weixin.MP.dll

    https://github.com/Senparc/WeiXinMPSDK [转] http://www.cnblogs.com/szw/archive/2013/01/13/senparc-wei ...

  6. [译] 用 Swift 创建自定义的键盘

    本文翻译自 How to make a custom keyboard in iOS 8 using Swift 我将讲解一些关于键盘扩展的基本知识,然后使用iOS 8 提供的新应用扩展API来创建一 ...

  7. 删除.gitignore中的在version control中的文件

    如果有一个文件例如xyz在版本控制系统中,然后你发现这个文件不应该提交到git上,所以加了.gitignore文件并将其加入其中,但是git不会自动讲其从版本库中移除它.如果你只有一个文件,你可以使用 ...

  8. unity3d 日志捕捉

    public class Test : MonoBehaviour { public string output = ""; public string stack = " ...

  9. C# 调用导致堆栈不对称。原因可能是托管的 PInvoke 签名与非托管的目标签名不匹配

    在dllimport中加入CallingConvention参数就行了,[DllImport(PCAP_DLL, CharSet = CharSet.Auto, CallingConvention = ...

  10. @media screen解决移动web开发的多分辨率问题

    当今移动设备的发展已经越来越迅速,移动web开发的需求也越来越多多.许多大平台.大门户都纷纷推出了自己的移动web版网站. 随着移动设备飞速的发展,移动产品的屏幕规格越来越多.从几年前的320×240 ...