声明:本文内容纯属个人观点,官方保留最终解释

在上文(Discuz!NT URL地址重写) 中, 聊到了“在线用户”功能,因为当时介绍的重点不是“在线”
那一块,所以没做深入介绍。这就为今天这篇文章埋下了“伏笔”。因为在线这个功能太重要了,大家不妨
用VS打开我们产品的最新源码,然后搜索一下“OnlineUsers.”这个内容就会看到它在产品中被使用的“频
率”。
 
     好了,言归正传,下面就开始接着上一篇文章中所说的“OnlineUsers.ResetOnlineList();” 方法介绍
一下用户在线功能。

首先请大家打开Discuz.Forum这个项目,从中找到"OnlineUsers.cs"这个文件,打开它找到
"ResetOnlineList()"这个函数,它的代码如下:

 1  /**//// <summary>
 2  /// 复位在线表, 如果系统未重启, 仅是应用程序重新启动, 则不会重新创建
 3  /// </summary>
 4  /// <returns></returns>
 5  public static int ResetOnlineList()
 6  {
 7   try
 8   {
 9    // 取得在线表最后一条记录的tickcount字段 (因为本功能不要求特别精确)
10                  //int tickcount = DatabaseProvider.GetInstance().GetLastTickCount();
11    // 如果距离现在系统运行时间小于10分钟
12    if (System.Environment.TickCount < 600000)
13    {
14     return InitOnlineList();
15    }
16    return -1;
17   }
18   catch
19   {
20    try
21    {
22     return InitOnlineList();
23    }
24    catch
25    {
26     return -1;
27    }
28   }
29
30  }
31
32

这个函数本身就是在系统启动之后的10分钟内运行InitOnlineList函数,而为什么是10分钟(
不是别的时间段呢?),主要是因为这个值是个“估计值”,因为在线功能是系统的核心功能之一,
换句话说,系统在启动10分钟内,只要是用户在前台进行操作,绝对会用到这个核心功能,而这个
功能本身是依赖于数据库中的“dnt_onlines"表的(如果大家想了解这个表的结构,可以下载我们
产品的“数据字典”,里面有这方面内容的介绍)。所以创建(复位)和初始化这个数据表的责任就
交给了ResetOnlineList()这个函数(因为它是在HttpModule.cs中被绑定的,可以看作是系统运行
的起点,详情见上文)。

好了,即然清楚了这个函数的作用,不妨再了解一下代码中InitOnlineList()方法,它的作用
就是运行下面这个SQL语句:

 1//该函数位于Discuz.Data.SqlServer项目中的UserManage.cs文件中
 2 public int CreateOnlineTable() 
 3        {
 4            try
 5            {
 6                StringBuilder sb = new StringBuilder();
 7                sb.Append("IF EXISTS (SELECT * FROM SYSOBJECTS WHERE id = object_id(N'[dnt_online]') AND OBJECTPROPERTY(id, N'IsUserTable') = 1) DROP TABLE [dnt_online];");
 8                sb.Append("CREATE TABLE [dnt_online] ([olid] [int] IDENTITY (1, 1) NOT NULL,[userid] [int] NOT NULL,[ip] [varchar] (15) NOT NULL,[username] [nvarchar] (20) NOT NULL,[nickname] [nvarchar] (20) NOT NULL,[password] [char] (32) NOT NULL,[groupid] [smallint] NOT NULL,[olimg] [varchar] (80) NOT NULL,[adminid] [smallint] NOT NULL,[invisible] [smallint] NOT NULL,[action] [smallint] NOT NULL,[lastactivity] [smallint] NOT NULL,[lastposttime] [datetime] NOT NULL,[lastpostpmtime] [datetime] NOT NULL,[lastsearchtime] [datetime] NOT NULL,[lastupdatetime] [datetime] NOT NULL,[forumid] [int] NOT NULL,[forumname] [nvarchar] (50) NOT NULL,[titleid] [int] NOT NULL,[title] [nvarchar] (80) NOT NULL,[verifycode] [varchar] (10) NOT NULL ) ON [PRIMARY];");
 9                sb.Append("ALTER TABLE [dnt_online] WITH NOCHECK ADD CONSTRAINT [PK_dnt_online] PRIMARY KEY CLUSTERED ([olid]) ON [PRIMARY]; ");
10                sb.Append("ALTER TABLE [dnt_online] ADD CONSTRAINT [DF_dnt_online_userid] DEFAULT ((-1)) FOR [userid],CONSTRAINT [DF_dnt_online_ip] DEFAULT ('0.0.0.0') FOR [ip],CONSTRAINT [DF_dnt_online_username] DEFAULT ('') FOR [username],CONSTRAINT [DF_dnt_online_nickname] DEFAULT ('') FOR [nickname],CONSTRAINT [DF_dnt_online_password] DEFAULT ('') FOR [password],CONSTRAINT [DF_dnt_online_groupid] DEFAULT (0) FOR [groupid],CONSTRAINT [DF_dnt_online_olimg] DEFAULT ('') FOR [olimg],CONSTRAINT [DF_dnt_online_adminid] DEFAULT (0) FOR [adminid],CONSTRAINT [DF_dnt_online_invisible] DEFAULT (0) FOR [invisible],CONSTRAINT [DF_dnt_online_action] DEFAULT (0) FOR [action],CONSTRAINT [DF_dnt_online_lastactivity] DEFAULT (0) FOR [lastactivity],CONSTRAINT [DF_dnt_online_lastposttime] DEFAULT ('1900-1-1 00:00:00') FOR [lastposttime],CONSTRAINT [DF_dnt_online_lastpostpmtime] DEFAULT ('1900-1-1 00:00:00') FOR [lastpostpmtime],CONSTRAINT [DF_dnt_online_lastsearchtime] DEFAULT ('1900-1-1 00:00:00') FOR [lastsearchtime],CONST  RAINT [DF_dnt_online_lastupdatetime] DEFAULT (getdate()) FOR [lastupdatetime],CONSTRAINT [DF_dnt_online_forumid] DEFAULT (0) FOR [forumid],CONSTRAINT [DF_dnt_online_forumname] DEFAULT ('') FOR [forumname],CONSTRAINT [DF_dnt_online_titleid] DEFAULT (0) FOR [titleid],CONSTRAINT [DF_dnt_online_title] DEFAULT ('') FOR [title],CONSTRAINT [DF_dnt_online_verifycode] DEFAULT ('') FOR [verifycode];");
11                sb.Append("CREATE INDEX [forum] ON [dnt_online]([userid], [forumid], [invisible]) ON [PRIMARY];");
12                sb.Append("CREATE INDEX [invisible] ON [dnt_online]([userid], [invisible]) ON [PRIMARY];");
13                sb.Append("CREATE INDEX [forumid] ON [dnt_online]([forumid]) ON [PRIMARY];");
14                sb.Append("CREATE INDEX [password] ON [dnt_online]([userid], [password]) ON [PRIMARY];");
15                sb.Append("CREATE INDEX [ip] ON [dnt_online]([userid], [ip]) ON [PRIMARY];");
16
17                return DbHelper.ExecuteNonQuery(CommandType.Text, sb.Replace("dnt_", BaseConfigs.GetBaseConfig().Tableprefix).ToString());
18            }
19            catch
20            {
21                return -1;
22            }
23        }
24
25

该方法如果正常运行的话,会在数据库中建立dnt_onlines"这个表。用于记录在线用户的全部
信息。

上文介绍的仅仅是系统“初始化”时所要做的“活”。而更重要的内容是用户从一访问论坛并
执行一系列操作(如登陆,发贴,浏览版块等)时,“在线用户”机制在里面所启的重要作用。

这里先以登陆(系统)这一操作发生时,程序所做出的响应为例,看一下在线这块是如何进行绑
定的,请看如下代码(位于discuz.web项目的“aspx/1/”文件夹下的login.aspx.cs文件):

1
2    OnlineUsers.UpdateAction(olid, UserAction.Login.ActionID, 0, config.Onlinetimeout);
3    
4

它的作用就是将已成功登陆系统的用户所执行的当前动作及相关信息更新到"dnt_onlines" 表
中。而这个函数本身所用到的四个参数要重点介绍一下:

olid: 在线列表id,对应"dnt_onlines"表中的olid字段

action:动作(结构类型,详情参见discuz.forum项目下的forumutils.cs文件)
           用于传递动作的相关信息如:ActionName动作名称和ActionDescription动作描述等)

inid: 所在位置代码,即当前用户所访问的主题(TopicId)。因为登陆不牵扯主题操作,所
           以上面的值为0

timeout: 无动作离线时间(config.Onlinetimeout),这个数据是在后台进行设置的,见下图:

timeout的作用就是当有别人访问论坛时,在更新自身在线状态信息同时,用这个设置数据(
整型)与在线表(dnt_onlines)中的"lastupdatetime"字段(最后活动时间)进行比较,找出超过
timeout规定的时间的用户,将其在线状态(onlinestate)设置为0(即为离线)。而做这件事的函
数就是在项目“discuz.data.sqlserver”下的“UserManage.cs”中的“AddOnlineUser”函数,这
里将它的代码贴出来,详情见注释:

 1/**//// <summary>
 2        /// 执行在线用户向表及缓存中添加的操作。
 3        /// </summary>
 4        /// <param name="__onlineuserinfo">在组用户信息内容</param>
 5        /// <returns>添加成功则返回刚刚添加的olid,失败则返回0</returns>
 6        public int AddOnlineUser(OnlineUserInfo __onlineuserinfo, int timeout)
 7        {
 8
 9            string strDelTimeOutSql = "";
10            // 此处的设置见后台forum_uisetting.aspx.cs源码
11            // 如果timeout为负数则代表不需要精确更新用户是否在线的状态
12            if (timeout > 0)
13            {
14                if (__onlineuserinfo.Userid > 0)
15                {
16                    strDelTimeOutSql = string.Format("{0}UPDATE [{1}users] SET [onlinestate]=1 WHERE [uid]={2};", strDelTimeOutSql, BaseConfigs.GetTablePrefix, __onlineuserinfo.Userid.ToString());
17                }
18            }
19            else
20            {
21                timeout = timeout * -1;
22            }
23
24            if (timeout > 9999)
25            {
26                timeout = 9999;
27            }
28
29            System.Text.StringBuilder sb = new System.Text.StringBuilder();
30            System.Text.StringBuilder sb2 = new System.Text.StringBuilder();
31
32            IDataReader dr = DbHelper.ExecuteReader(CommandType.Text, string.Format("SELECT [userid] FROM [{0}online] WHERE [lastupdatetime]<'{1}'", BaseConfigs.GetTablePrefix, DateTime.Parse(DateTime.Now.AddMinutes(timeout * -1).ToString("yyyy-MM-dd HH:mm:ss"))));
33            try
34            {
35                while (dr.Read())
36                {
37                    sb.Append(",");
38                    sb.Append(dr[0].ToString());
39                    if (dr[0].ToString() != "-1")
40                    {
41                        sb2.Append(",");
42                        sb2.Append(dr[0].ToString());
43                    }
44                }
45            }
46            finally
47            {
48                dr.Close();
49            }
50
51            if (sb.Length > 0)
52            {
53                sb.Remove(0, 1);
54                strDelTimeOutSql = string.Format("{0}DELETE FROM [{1}online] WHERE [userid] IN ({2});", strDelTimeOutSql, BaseConfigs.GetTablePrefix, sb.ToString());
55            }
56            if (sb2.Length > 0)
57            {
58                sb2.Remove(0, 1);
59                strDelTimeOutSql = string.Format("{0}UPDATE [{1}users] SET [onlinestate]=0,[lastactivity]=GETDATE() WHERE [uid] IN ({2});", strDelTimeOutSql, BaseConfigs.GetTablePrefix, sb2.ToString());
60            }
61
62
63            DbParameter[] prams = {};
64            int olid = Utils.StrToInt(DbHelper.ExecuteScalar(CommandType.Text, strDelTimeOutSql + "INSERT INTO [" + BaseConfigs.GetTablePrefix + "online] ([userid],[ip],[username],[nickname],[password],[groupid],[olimg],[adminid],[invisible],[action],[lastactivity],[lastposttime],[lastpostpmtime],[lastsearchtime],[lastupdatetime],[forumid],[forumname],[titleid],[title], [verifycode])VALUES(@userid,@ip,@username,@nickname,@password,@groupid,@olimg,@adminid,@invisible,@action,@lastactivity,@lastposttime,@lastpostpmtime,@lastsearchtime,@lastupdatetime,@forumid,@forumname,@titleid,@title,@verifycode);SELECT SCOPE_IDENTITY()", prams).ToString(), 0);
65
66            // 如果id值太大则重建在线表
67            if (olid > 2147483000)
68            {
69                CreateOnlineTable();
70                DbHelper.ExecuteNonQuery(CommandType.Text, strDelTimeOutSql + "INSERT INTO [" + BaseConfigs.GetTablePrefix + "online] ([userid],[ip],[username],[nickname],[password],[groupid],[olimg],[adminid],[invisible],[action],[lastactivity],[lastposttime],[lastpostpmtime],[lastsearchtime],[lastupdatetime],[forumid],[titleid],[verifycode])VALUES(@userid,@ip,@username,@nickname,@password,@groupid,@olimg,@adminid,@invisible,@action,@lastactivity,@lastposttime,@lastpostpmtime,@lastsearchtime,@lastupdatetime,@forumid,@forumname,@titleid,@title,@verifycode);SELECT SCOPE_IDENTITY()", prams);
71                return 1;
72            }
73
74
75            return 0;
76            //return (int)DbHelper.ExecuteDataset(CommandType.Text, "SELECT [olid] FROM ["+BaseConfigFactory.GetTablePrefix+"online] WHERE [userid]=" + __onlineuserinfo.Userid.ToString()).Tables[0].Rows[0][0];
77
78        }
79
80

需要说明一下,就是在线表的删除问题。因为这个在线表是通过程序在数据库中进行创建的,
同时表中的olid又是一个自增字段(标识自增为1),因此为了避免自增字段最终超过最大值范围
(因为在线表经常有数据添加进来)。所以在上面加入了"olid > 2147483000"的逻辑判断,来预
防这个问题的出现。

说了一大堆的关于timeout参数的问题,而另一个重要的参数olid还没作详细介绍呢:)

上面所述的登陆页面(login.aspx.cs)中,olid是从basepage类中获得的,而basepage就是前
台主要页面的“基类”,它里面的构造函数部分封装了页面中大部分公共变量的初始化操作。所以要
了解olid,还要从basepage.cs中分析一把。

请看下面的代码段(摘自discuz.web.ui项目下的basepage.cs文件):

 1/**//// <summary>
 2    /// 当前用户的在线表ID
 3    /// </summary>
 4    protected internal int olid;
 5
 6    public BasePage() //构造函数
 7    {
 8      
 9      oluserinfo = OnlineUsers.UpdateInfo(config.Passwordkey, config.Onlinetimeout);
10      
11      //password 可用于下面的userkey赋值,以实现用户退出操作时的识别认证
12      password = oluserinfo.Password;  
13      if (password.Length > 16)
14      {
15  userkey = password.Substring(4, 8).Trim();
16      }
17      else
18      {
19  userkey = "";
20      }
21
22     
23      olid = oluserinfo.Olid;
24      
25    } 
26
27

从代码中可以看出olid是通过louserinfo对象进行赋值的,而louserinfo对象是通过UpdateInfo
来进行实始化绑定的,所以我们还需要再看一下这个函数,相关代码段如下:

 1  /**//// <summary>
 2  /// 用户在线信息维护。判断当前用户的身份(会员还是游客),是否在在线列表中存在,如果存在则更新会员的当前动,不存在则建立.
 3  /// </summary>
 4  /// <param name="passwordkey">论坛passwordkey</param>
 5  /// <param name="timeout">在线超时时间</param>
 6  /// <param name="passwd">用户密码</param>
 7  public static OnlineUserInfo UpdateInfo(string passwordkey, int timeout, int uid, string passwd)
 8  {
 9
10   lock(SynObject)
11   {
12    OnlineUserInfo __onlineuser = new OnlineUserInfo();
13   
14    string ip = DNTRequest.GetIP();
15    int userid = Utils.StrToInt(ForumUtils.GetCookie("userid"), uid);
16    string password = (passwd == string.Empty ? ForumUtils.GetCookiePassword(passwordkey) : ForumUtils.GetCookiePassword(passwd,passwordkey));
17
18    if (password.Length == 0)
19    {
20     userid = -1;
21    }
22     // 如果密码非Base64编码字符串则怀疑被非法篡改, 直接置身份为游客
23    else if (!Utils.IsBase64String(password))
24    {
25     userid = -1;
26    }
27
28    if (userid != -1)
29    {
30     __onlineuser = GetOnlineUser(userid,password);
31     if (__onlineuser != null)
32     {
33      
34      if (__onlineuser.Ip != ip)
35      {
36       UpdateIP(__onlineuser.Olid, ip);
37
38       __onlineuser.Ip = ip;
39     
40       return __onlineuser;
41      }
42     }
43     else
44     {
45      
46      // 判断密码是否正确
47      userid = Users.CheckPassword(userid, password, false);
48      if (userid != -1)
49      {
50       DeleteRowsByIP(ip);
51       return CreateUser(userid, timeout);
52      }
53      else
54      {
55       // 如密码错误则在在线表中创建游客
56       __onlineuser = GetOnlineUserByIP(-1, ip);
57       if (__onlineuser == null)
58       {
59        return CreateGuestUser(timeout);
60       }
61      }
62     }
63
64    }
65    else
66    {
67     __onlineuser = GetOnlineUserByIP(-1, ip);
68     if (__onlineuser == null)
69     {
70      return CreateGuestUser(timeout);
71     }
72
73    }
74
75    __onlineuser.Lastupdatetime = Utils.GetDateTime();
76    return __onlineuser;
77  
78   }
79
80  }
81
82

看到这里大家明白了吧,原来不管用户是否注册登陆,这个函数都会将一些信息更新或添加到在线
表中。即判断当前用户的身份(会员还是游客),是否在"在线列表"中存在,如果存在则更新会员的当前动作,
不存在(首次访问)则初始化相关(游客)用户信息。

下面再介绍一下action这个参数,它是结构(struct)类型,里面的ActionName动作名称和ActionD-
escription动作描述(目前未用上)是用于显示当前动作信息的。相应的显示效果如下图所示:

如果大家觉得没问题的话,下面再介绍一下注销(退出)操作,因为有登陆就会有退出。而注销这
块的操作也很简单,请看如下代码段(位于aspx/1/logout.aspx.cs文件):

 1public class logout : BasePage
 2    {
 3        protected override void ShowPage()
 4        {
 5            
 6
 7            if (DNTRequest.GetString("userkey") == userkey)
 8            {
 9                AddMsgLine("已经清除了您的登录信息, 稍后您将以游客身份返回首页");
10                Users.UpdateOnlineTime(uid);
11                OnlineUsers.DeleteRows(olid);
12                ForumUtils.ClearUserCookie();
13                Utils.WriteCookie(Utils.GetTemplateCookieName(), "", -999999);
14            }
15            else
16            {
17                AddMsgLine("无法确定您的身份, 稍后返回首页");
18            }
19        }
20    }
21
22

代码中的userkey其实是一个用户password的一个子串(详情上面basepage.cs代码中的相应部分)。
    而“OnlineUsers.DeleteRows(olid);”这行代码其实就是删除在线表中指定olid的用户信息了。因
为代码过于简单,只是一条SQL语句而已,所以就不在这里多费笔默了。

其实关于在线表有关的操作还有很多,大家不妨挖一下onlines.cs这个文件,从中会有更多的收获。

最后再介绍一下有关“最大在线人数”这个问题,其实这个功能主要是为了中小站长(服务器资源相
对紧张)提供的一项设置,旨在当用户在线人数达到一定数量时,拒绝其它的访问。相应的代码判断逻
辑如下(摘自basepage.cs文件):

 1 if (config.Onlinetimeout > 0 && userid != -1)
 2 {
 3  onlineusercount = OnlineUsers.GetOnlineAllUserCount();
 4 }
 5    else
 6 {
 7  onlineusercount = OnlineUsers.GetCacheOnlineAllUserCount();
 8 }
 9    if (onlineusercount >= config.Maxonlines && useradminid != 1 && pagename != "login.aspx" && pagename != "logout.aspx")
10 {
11  ShowMessage("抱歉,目前访问人数太多,你暂时无法访问论坛.", 0);
12  return;
13 }
14

里面的GetOnlineAllUserCount()和GetCacheOnlineAllUserCount()均为返回在线人数的方法,而
config.Onlinetimeout的设置是在管理后台完成的,见下图:

好了,今天的文章就先写到这里了,希望大家不要感觉是在“云里雾里”的:),如果有问题欢迎
与我交流或去我们的官方站点(http://nt.discuz.net)反映问题。

我的email:  daizhj@discuz.com,  daizhj617595@126.com, daizhj@gmail.com

关键字:.net,discuz,disucznt,online,在线,在线用户

作者:代震军,daizhj

Discuz!NT 在线用户功能简介相关推荐

  1. Discuz!NT - 在线显示列表 游客 bug 修复

    引发bug的条件:当你修改了系统组里面的[游客]组 的名字后!! 你会发现首页上底部的在线显示列表里始终都是显示"游客"字样而非你改过得字样!如图 至此你需要运行一个t-sql脚本 ...

  2. 【转载】Discuz!NT企业版之Sphinx全文搜索

    Discuz!NT企业版之Sphinx全文搜索(上) 作为Discuz!NT企业版中的一员,在设计企业级搜索架构之初,就考虑了海量数量,准实时索引更新,并发访问,安装布署等诸多方面.目前在生产环境下被 ...

  3. discuz NT!整合

    在看过这篇文章 http://www.jb51.net/article/20851.htm 和这篇文章 http://www.jb51.net/article/20850.htm 按上述文章的描述,先 ...

  4. 华为云计算IE面试笔记-华为云迁移工具Rainbow功能简介。支持哪些虚拟化平台和操作系统的迁移?支持哪些业务迁移方式?Windows在线迁移和Linux在线迁移前针对OS需要做哪些检查?

    1. 功能简介:Rainbow迁移工具是华为自研的基于操作系统层面的迁移工具,提供将主机(X86架构服务器)系统及数据或其它虚拟化平台的业务系统完整地.在线不中断地迁移到华为FusionSphere虚 ...

  5. php ldap 登陆验证,LDAP用户验证功能简介

    LDAP功能是依赖于PHP的LDAP扩展,所以要加载LDAP扩展, 具体可以参考 安装PHP的LDAP扩展 一.功能简介 通过配置LDAP,实现ldap服务器的用户自动登录.也可以从ldap导入用户. ...

  6. JAVA实现QQ:实现文字聊天、QQ用户登录、拉取在线用户列表、无异常退出、私聊、发文件、下载文件、离线留言、服务端推送新闻等功能(后端无界面,Utilty源码在后面、)

    这个仿QQ项目是参考韩顺平老师的多线程课程做的,因为个人觉得非常有意义特别是让我对多线程通信又了一个新的理解因此我准备写一篇总结(如果觉得视频太长可以参考下): 具体视频地址:大家给韩老师一键三连[韩 ...

  7. 在项目中使用 Discuz!NT的上传头像功能

    大概半年前,由于某个网站项目需要整合Discuz!NT,就粗略的用了一下.觉得里面的会员上传头像功能方便好用,而且支持摄像头,就把它的代码分离出来,以后用在需要的地方. 用过Discuz!NT的朋友会 ...

  8. ldap 单点登录 php,LDAP用户验证功能简介

    LDAP功能是依赖于PHP的LDAP扩展,所以要加载LDAP扩展, 具体可以参考 安装PHP的LDAP扩展 一.功能简介 通过配置LDAP,实现ldap服务器的用户自动登录.也可以从ldap导入用户. ...

  9. Discuz!NT负载均衡方案

    在前面的几篇文章中,主要谈到了在Discuz!NT中的跨站缓存数据,数据库负载均衡.但如果要实现将产品分布式布置到若干机器,组成集群来共同支撑起整个业务的话,还是有一定问题的(后面会有所介绍).下面先 ...

最新文章

  1. 继人工智能攻陷围棋,德州扑克也沦陷了
  2. 将你的 CentOS 变成 OSPF 路由器
  3. MySql级联删除和更新
  4. C语言字符像素,返回字符串宽度 (以像素为单位)
  5. JVM笔记(一)数字在JVM中的表示
  6. SpaceX提交星链项目修订申请,计划用星际飞船发射3万颗卫星
  7. 要成为linux网站运维工程师必须要掌握的技能
  8. [转载] np.logical_and用法(有代码)
  9. 腾讯社交广告大赛回来的感悟
  10. BIOS升级,差一点也不行
  11. 北理工计算机学院奖学金公示,计算机学院2020年研究生国家奖学金拟推荐人选公示通知...
  12. 数字转换为中文大写(钱数)
  13. 一键重装系统win8图文教程
  14. 图解通信原理与案例分析-29:埃隆.马斯克的“星链”Starlink计划是卫星语音通信向卫星互联网的演进
  15. (十一)IPSec协议
  16. java-jacob操作word,往word中动态插入各种文件
  17. /(^\s*)|(\s*$)/g
  18. wps如何放大导航窗格字体
  19. mysql防注入插件_MyBB HM_My Country Flags 插件'cnam'参数SQL注入漏洞
  20. 时序逻辑电路二——数字逻辑实验

热门文章

  1. 学习quartz定时
  2. [Android Studio 权威教程]Windows下安装Android Studio
  3. C语言中do...while(0)用法小结
  4. T-SQL DISTINCT
  5. The Fuctions of LWAPP
  6. 新一代数据中心设计技术研讨会
  7. Silverlight学习之——事件编程
  8. typedef VS #define —— C语言中的 关键字 与 C指令
  9. C# 不能从数据库更新实体
  10. C++11实战——多线程的日志类