以文本方式查看主题

-  Foxtable(狐表)  (http://foxtable.net/bbs/index.asp)
--  专家坐堂  (http://foxtable.net/bbs/list.asp?boardid=2)
----  移动端+PC端的并发独占编辑思路有必要问一下。  (http://foxtable.net/bbs/dispbbs.asp?boardid=2&id=97191)

--  作者:chen3728060
--  发布时间:2017/3/7 18:20:00
--  移动端+PC端的并发独占编辑思路有必要问一下。
网络下复杂编号的已经解决,这个很简单,因为以前在OpenQQ时就是客户端发消息请求服务器端发送一个最新的编号过去,先在既然httpRequest请求都直接是服务器收到,那服务器可以直接从编号的字典里,给出最新的编号

Public flbhs As New Dictionary(of String,Integer)


以前OpenQQ就是用上面这个字典存编号


Dim msg As String = e.Message

If msg.StartsWith(":f") AndAlso msg.EndsWith("f:") Then
    msg = msg.SubString(2, msg.Length - 4)
    If pdbhs.ContainsKey(msg) Then \'

    msg = msg.SubString(2, msg.Length - 4)

    If pdbhs.ContainsKey(msg) Then \'如果存在这个类别的编号

        pdbhs(msg) = pdbhs(msg) + 1 \'将该类别最大编号加1

    Else

        pdbhs.Add(msg,1) \'如果是这个列表的首次编号,则编号等于1

    End If
    e.ReturnValue = pdbhs(msg)

    e.ReturnValue = pdbhs(msg) \'将编号返回给客户端

End If


用上面的代码获取编号,现在只需要稍微改造一下,就可以给新编号。


不过我想问的是,独占编辑的思路,尤其是防止客户掉线后防止死锁的问题。



Public tbrk As new Dictionary(of String,String)

tbrk是一个字典,用于登记每一行是谁在编辑。

我们约定接下来编码的时候:字典的键由表名和行的主键组合成,值则等于编辑者名。



在OpenQQ,用了一个字典来登记谁在编辑。客户端要编辑,就会问服务器端谁在编辑,没人就登记一下,我编辑。在移动端这个问题很容易解决,收到HttpRequest时,也通过这个字典判断是否有人在编辑这行,没有就跳转编辑htm,有就弄个TopTips提示拒绝客户即可,容易。


问题在于客户掉线的死锁。在openQQ下,有个30秒的心跳机制,超时死亡了,就会执行UserLogout事件,把客户踢出这个独占编辑字典

Dim Keys As New List(of String)

For Each Key As String In tbrk.Keys
   If tbrk(Key) = e.UserName Then
      Keys.Add(Key)
    End
If

   If tbrk(Key) = e.UserName Then

      Keys.Add(Key)

    End If

Next

For Each Key As String In Keys

    tbrk.Remove(Key)

Next



但是在移动端对于客户存活状态判断,在新帮助文档的→WeUi框架→让登陆变得更加安全,

设计思路

1、服务端新建一个临时表,包括三列,分别是:UserName,UserID和ActiveTime

2、服务端在验证用户身份后,在临时表中新增一行,生成一个16位的随机字符串存储在UserID列,用户名和当前时间则分别存储在UserName和ActiveTime列。

3、完成上述操作后,再将UserName和UserID保存在Cookie中,其中UserName存储在Cookie中的是加密后的字符串。

4、为方便理解,本节的示例代码直接使用username和userid作为Cookie名称,实际开发的时候,请采用没有任何指示性的名称,注意Cookie名是区分大小写的,这里用的是小写。

5、用户在登录成功,继续访问其他页面时,Cookie中会包括username和userid,服务端根据username和userid从临时表中查找对应的行,此时会有三种可能:

    • 如果找到,且ActiveTime和当前时间相比,相差不超过30分钟,允许访问,并将ActiveTime列更新为当前时间。
    • 如果找到,但ActiveTime和当前时间相比,相差已超过30分钟,拒绝访问,并删除此行,然后跳转到登录页面。
    • 如果没有找到,则拒绝访问,直接跳转到登录页面。

6、如果用户在其他位置登录成功,服务端根据加密后的UserName在临时表中查找对应的行,如果找到,说明是重复登录,删除此行,使得前一次的登录无效;然后重复2、3操作,在临时表和Cookie中存储加密后的UserName和随机生成的UserID,并在ActiveTime列记录当前时间。

7、显然临时表的记录会越来越多,我们可以定期清除ActiveTime列和当前时间相比超过30分钟的行,也可以在表在超过约定行数后执行一次清理动作,本示例选择的是前者,每30分钟清理一次


用的是每次收到HttpRequest时,判断是否有超时30分钟的人,有就把它踢出。既然判断他超时,就是认为他断线了,所以也就只能此时把用户踢出  独占编辑字典。

这样就出现一个问题。有个A领导,打开了某个出库单据准备审核,然后他的垃圾手机死机了,他烦了,于是去开会了。独占编辑字典里,已经登记了这个领导在编辑,没有超过30分钟,系统都不会认定他断线死亡。然后这30分钟内,领导B想审核这个单据,就会提示领导A一直在编辑,他就很纳闷,于是他去问A,A领导说“我没有在编辑,你看我手机都坏了,电脑我也没开啊”。B领导就继续纳闷,苦等了半个小时。这咋解决?

核心问题在于  openQQ的心跳机制可以让超时死亡控制在30秒,移动端的ActiveTime的超时死亡在30分钟,咋解决?

①把ActiveTime的时间缩短,但是带来问题就是有时候手机端录入速度确实慢,例如我去仓库一个个数产品数量盘点,然后填入数量,由于已经没有点提交按钮,不会有新的HttpRequest触发,盘点时间过长,导致我被踢出了独占编辑。其他人又用手机或者电脑打开了这个单据修改,我先保存,然后他后保存,覆盖了我的记录,我做的功夫全白费了

难道我放一个看不到的异步Ajax玩意,每30秒触发一下服务器?


---------------------------------------
群里有人推荐了我去看HttpClient,解决这个。但是我看HttpClient貌似不是用在手机端的,而是用来开发管理公众号后台客户端的工具。

求思路解答

--  作者:有点蓝
--  发布时间:2017/3/7 20:42:00
--  
使用js计时器,按指定的间隔向服务器发送信息表示在线:http://www.w3school.com.cn/js/js_timing.asp



--  作者:chen3728060
--  发布时间:2017/3/7 21:36:00
--  回复:(有点蓝)使用js计时器,按指定的间隔向服务器...
如果是要用js实现心跳,这个东西太重要,希望狐爸把它整合进去
--  作者:有点蓝
--  发布时间:2017/3/7 22:39:00
--  
这种东西可能不好整合,参考用法

HttpRequest事件代码:

\'通用事件头,用于发送已经存在的常见文件
Dim fl As String = "c:\\web\\" & e.path
If filesys.FileExists(fl)
    Dim idx As Integer = fl.LastIndexOf(".")
    Dim ext As String  = fl.SubString(idx)
    Select Case ext
        Case ".jpg",".gif",".png",".bmp",".wmf",".js",".css" ,".html",".htm",".zip",".rar"  
            e.WriteFile(fl)
            Return \'这里必须返回
    End Select
End If
Select Case e.Path
    Case "count.htm"
        Dim wb As New weui
        Dim sb As New StringBuilder
        sb.AppendLine("<script src=\'http://cdn.static.runoob.com/libs/jquery/1.10.2/jquery.min.js\'></script>")
        sb.AppendLine("<script>")
        sb.AppendLine("var c=0;")
        sb.AppendLine("var t;")
        sb.AppendLine("function timedCount(){")
        sb.AppendLine("document.getElementById(\'xm\').value=c;")
        sb.AppendLine("c=c+1;")
        sb.AppendLine("sendAjaxText(\'1\',\'active.htm\',\'\',false);")
        sb.AppendLine("t=setTimeout(\'timedCount()\',2000);")
        sb.AppendLine("}")
        sb.AppendLine("$(document).ready(function () {")
        sb.AppendLine("timedCount();")
        sb.AppendLine("});")
        sb.AppendLine("</script>")
        wb.AppendHTML(sb.ToString,True)
        With wb.AddInputGroup("","ipg1","计时")
            .AddInput("xm","0","text").Readonly = True
        End With
        e.WriteString(wb.Build) \'生成网页
    Case "active.htm"
        StatusBar.Message2 = val(StatusBar.Message2) + 1
End Select

--  作者:zhangjian222200
--  发布时间:2017/8/28 20:28:00
--  
发错了
[此贴子已经被作者于2017/8/28 20:28:38编辑过]

--  作者:zhy400137
--  发布时间:2017/8/28 20:43:00
--  
mark