惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
News and Events Feed by Topic
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
月光博客
月光博客
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
大猫的无限游戏
大猫的无限游戏
T
Tailwind CSS Blog
S
SegmentFault 最新的问题
V
V2EX
阮一峰的网络日志
阮一峰的网络日志
C
Cisco Blogs
博客园 - 叶小钗
P
Privacy International News Feed
Jina AI
Jina AI
Apple Machine Learning Research
Apple Machine Learning Research
T
Threatpost
IT之家
IT之家
博客园 - 聂微东
Know Your Adversary
Know Your Adversary
Help Net Security
Help Net Security
罗磊的独立博客
I
Intezer
S
Schneier on Security
博客园_首页
C
CERT Recently Published Vulnerability Notes
雷峰网
雷峰网
Cisco Talos Blog
Cisco Talos Blog
宝玉的分享
宝玉的分享
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Webroot Blog
Webroot Blog
TaoSecurity Blog
TaoSecurity Blog
MyScale Blog
MyScale Blog
P
Privacy & Cybersecurity Law Blog
T
The Exploit Database - CXSecurity.com
PCI Perspectives
PCI Perspectives
Security Latest
Security Latest
H
Heimdal Security Blog
S
Secure Thoughts
Hacker News: Ask HN
Hacker News: Ask HN
Y
Y Combinator Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
Microsoft Security Blog
Microsoft Security Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
SecWiki News
SecWiki News
The GitHub Blog
The GitHub Blog
A
Arctic Wolf
A
About on SuperTechFans
aimingoo的专栏
aimingoo的专栏
T
Threat Research - Cisco Blogs
Engineering at Meta
Engineering at Meta
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC

博客园 - 可可果

Java Annotation手册 .NET环境下五种邮件发送解决方案(转载) C#中的事务处理 - 可可果 - 博客园 用commons-fileupload-1.2 实现文件上传(适用于Trubine框架) 用JAVA实现文本形式的树状结构显示(转) Google十大搜索技巧 Javascript导出Excel的方法 - 可可果 - 博客园 理解session机制 session的工作原理(转载) Session监听 button添加链接的方法 - 可可果 - 博客园 获得select控件的文本值的方法 - 可可果 - 博客园 清除缓存的方法 - 可可果 - 博客园 Java中Excel导出时文件名乱码问题的解决 单例模式陷阱(转载) java模式中的单例模式(转载) - 可可果 - 博客园 Java开发中,试用hibernate建立关联时出现:not-null property references a null or transient value异常的原因 ListBox之间进行传值的脚本的例子,一般在添加权限,行业或者多项时可以用到 - 可可果 - 博客园 Velocity基本语法
解决用户意外退出在线列表无法及时更新问题(转载)
可可果 · 2007-12-03 · via 博客园 - 可可果

  1 一般来说,用户离开系统的方式有三种:主动注销、会话超时、直接关闭浏览器,对于前两种,我们很容易便可将该用户从在线列表中清除,关键是第三种(很多用户都是直接关闭窗口的~~郁闷ing),程序无法捕获窗口关闭的精确时间,只能等到会话超时后在能将该用户清除出在线列表,假设我们设置会话超时时间为60分钟,而用户登陆系统随便浏览一个页面就以关闭浏览器的方式退出的话,我们要在将近1小时后才能从在线列表中将该用户清除出去(想象一下,系统显示n多人在线,可能除了你之外其他的n-1人都关机走人了,汗一个先```),而本文将尝试寻找一个解决方案把这种尴尬降至最低。
  2     我的大概思路是,给每在线用户增加一个RefreshTime属性,建立一个负责将当前用户的RefreshTime属性设置为当前时间的单独页面(Refresh.aspx),然后在系统的主要页面(也可以是所有页面)中通过xmlhttp不断地请求Refresh.aspx页面,一旦用户关闭了与本系统相关的所有窗口,即以直接关闭浏览器的方式退出系统,那么该用户的RefreshTime属性便不会自动更新了,我们再设置一个自动刷新的超时时间(这个要比会话超时短很多_refreshTimeout),当发现某用户超过_refreshTimeout的时间没有自动刷新,就能判定该用户已经以直接关闭浏览器的方式退出了。
  3     假设我们设置会话超时时间为60分钟,自动刷新超时时间为1分钟,在客户端通过xmlhttp每隔25秒(之所以不设1分钟,是防止网速慢的时候访问 Refresh.aspx超时,个人感觉,不一定正确)访问一次Refresh.aspx页面,在用户登陆、用户注销、检测用户是否在线的时候都执行清理超时用户(包括会话超时和自动刷新超时)操作,这样一来,在线用户列表的统计误差就由60分钟降至1分钟了。
  4 
  5 ==========================================
  6 
  7  
  8 
  9 具体实现如下:
 10 
 11 
 12 1、 新建一个名为ActiveUser的类,存储单个活动用户数据。
 13 
 14 /// <summary>
 15  /// 单个在线用户数据,无法继承此类。
 16  /// </summary>
 17  public sealed class ActiveUser
 18  { 
 19   private readonly string _ticket;    //票据名称
 20   private readonly string _username;   //登陆用户名
 21   private readonly string _truename;   //登陆用户名
 22   private readonly string _roleid;    //角色
 23   private readonly DateTime _refreshtime;  //最新刷新时间
 24   private readonly DateTime _activetime;  //最新活动时间
 25   private readonly string _clientip;   //登陆IP
 26  
 27   public ActiveUser(string Ticket,string UserName,string TrueName,string RoleID,string ClientIP) {
 28    this._ticket=Ticket;
 29    this._username=UserName;
 30    this._truename=TrueName;
 31    this._roleid=RoleID;
 32    this._refreshtime=DateTime.Now;
 33    this._activetime=DateTime.Now;
 34    this._clientip=ClientIP;
 35   }
 36 
 37   public ActiveUser(string Ticket,string UserName,string TrueName,string RoleID,DateTime RefreshTime,DateTime ActiveTime,string ClientIP)  {
 38    this._ticket=Ticket;
 39    this._username=UserName;
 40    this._truename=TrueName;
 41    this._roleid=RoleID;
 42    this._refreshtime=RefreshTime;
 43    this._activetime=ActiveTime;
 44    this._clientip=ClientIP;
 45   }
 46  
 47   public string Ticket  { get{return _ticket;}  }
 48   public string UserName  { get{return _username;}  }
 49   public string TrueName  { get{return _truename;}  }
 50   public string RoleID  { get{return _roleid;}  }
 51   public DateTime RefreshTime { get{return _refreshtime;} }
 52   public DateTime ActiveTime { get{return _activetime;} }
 53   public string ClientIP  { get{return _clientip;}  }
 54 
 55  }
 56 
 57  
 58 
 59 
 60 2、 新建一个名为PassPort的类,存储在线用户列表。
 61 
 62 /// <summary>
 63  /// PassPort 存储在线用户列表。
 64  /// </summary>
 65  public class PassPort
 66  {
 67   private  static  DataTable  _activeusers;
 68   private  int  _activeTimeout;
 69   private  int  _refreshTimeout;
 70 
 71   /// <summary>
 72   /// 初始化在线用户表。
 73   /// </summary>
 74   private void userstableFormat()
 75   {
 76    if(_activeusers==null) {
 77     _activeusers  =  new  DataTable("ActiveUsers");
 78     DataColumn  myDataColumn;
 79     System.Type mystringtype;
 80     mystringtype = System.Type.GetType("System.String");
 81     System.Type mytimetype;
 82     mytimetype = System.Type.GetType("System.DateTime");
 83     myDataColumn  =  new  DataColumn("Ticket",mystringtype);
 84     _activeusers.Columns.Add(myDataColumn);
 85     myDataColumn  =  new  DataColumn("UserName",mystringtype);
 86     _activeusers.Columns.Add(myDataColumn);
 87     myDataColumn  =  new  DataColumn("TrueName",mystringtype);
 88     _activeusers.Columns.Add(myDataColumn);
 89     myDataColumn  =  new  DataColumn("RoleID",mystringtype);
 90     _activeusers.Columns.Add(myDataColumn);   
 91     myDataColumn  =  new  DataColumn("RefreshTime",mytimetype);
 92     _activeusers.Columns.Add(myDataColumn);
 93     myDataColumn  =  new  DataColumn("ActiveTime",mytimetype);
 94     _activeusers.Columns.Add(myDataColumn);
 95     myDataColumn  =  new  DataColumn("ClientIP",mystringtype);
 96     _activeusers.Columns.Add(myDataColumn);  
 97    }
 98   }
 99 
100   public PassPort()
101   {
102    userstableFormat(); //初始化在线用户表
103    //活动超时时间初始化 单位:分钟
104    try { _activeTimeout=int.Parse(ConfigurationSettings.AppSettings["ActiveTimeout"]); }
105    catch{ _activeTimeout=60; }  
106    //自动刷新超时时间初始化 单位:分钟
107    try { _refreshTimeout=int.Parse(ConfigurationSettings.AppSettings["RefreshTimeout"]); }
108    catch{ _refreshTimeout=1; }  
109   }
110 
111   //全部用户列表
112   public  DataTable  ActiveUsers
113   {
114    get{return  _activeusers.Copy();}
115   }
116  
117   /// <summary>
118   /// 新用户登陆。
119   /// </summary>
120   public void Login(ActiveUser user,bool SingleLogin)
121   {
122    DelTimeOut();  //清除超时用户
123    if(SingleLogin){
124     //若是单人登陆则注销原来登陆的用户
125     this.Logout(user.UserName,false);
126    }
127    DataRow myRow;
128    try
129    {
130     myRow  =  _activeusers.NewRow();   
131     myRow["Ticket"]  =  user.Ticket.Trim();
132     myRow["UserName"]  =  user.UserName.Trim();
133     myRow["TrueName"]  =  ""+user.TrueName.Trim();
134     myRow["RoleID"]  =  ""+user.RoleID.Trim();
135     myRow["ActiveTime"]  =  DateTime.Now;
136     myRow["RefreshTime"]  =  DateTime.Now;
137     myRow["ClientIP"]  =  user.ClientIP.Trim();
138     _activeusers.Rows.Add(myRow);
139    }
140    catch(Exception  e)
141    {
142     throw(new  Exception(e.Message));
143    } 
144    _activeusers.AcceptChanges();
145   
146   }
147 
148   /// <summary>
149   ///用户注销,根据Ticket或UserName。
150   /// </summary>
151   private void Logout(string strUserKey,bool byTicket)
152   {
153    DelTimeOut();  //清除超时用户
154    strUserKey=strUserKey.Trim();
155    string  strExpr;  
156    strExpr =byTicket ? "Ticket='" + strUserKey +"'" : "UserName='" + strUserKey + "'";
157    DataRow[]  curUser;
158    curUser  =  _activeusers.Select(strExpr);
159    if  (curUser.Length  >0  )
160    {
161     for(int  i  =  0;  i  <  curUser.Length;  i  ++)
162     {
163      curUser[i].Delete();
164     }
165    }
166    _activeusers.AcceptChanges();  
167   }
168 
169   /// <summary>
170   ///用户注销,根据Ticket。
171   /// </summary>
172   /// <param name="strTicket">要注销的用户Ticket</param>
173   public void Logout(string strTicket){
174    this.Logout(strTicket,true);
175   }
176 
177   /// <summary>
178   ///清除超时用户。
179   /// </summary>
180   private  bool DelTimeOut()
181   {  
182    string  strExpr;  
183    strExpr = "ActiveTime < '" + DateTime.Now.AddMinutes( 0 - _activeTimeout) + "'or RefreshTime < '"+DateTime.Now.AddMinutes( 0 - _refreshTimeout)+"'";  
184    DataRow[]  curUser;
185    curUser  =  _activeusers.Select(strExpr);
186    if  (curUser.Length  >0  )
187    {
188     for(int  i  =  0;  i  <  curUser.Length;  i  ++)
189     {
190      curUser[i].Delete();    
191     }
192    }
193    _activeusers.AcceptChanges();
194    return  true;
195   }
196 
197   /// <summary>
198   ///更新用户活动时间。
199   /// </summary>
200   public  void  ActiveTime(string  strTicket)
201   {
202    DelTimeOut();
203    string  strExpr;
204    strExpr  =  "Ticket='"  +  strTicket  +  "'"
205    DataRow[]  curUser;
206    curUser  =  _activeusers.Select(strExpr);
207    if  (curUser.Length  >0  )
208    {
209     for(int  i  =  0;  i  <  curUser.Length;  i  ++)
210     {
211      curUser[i]["ActiveTime"]=DateTime.Now;
212      curUser[i]["RefreshTime"]=DateTime.Now;
213     }
214    }
215    _activeusers.AcceptChanges();
216   }
217 
218   /// <summary>
219   ///更新系统自动刷新时间。
220   /// </summary>
221   public  void  RefreshTime(string  strTicket)
222   {
223    DelTimeOut();
224    string  strExpr;
225    strExpr  =  "Ticket='"  +  strTicket  +  "'"
226    DataRow[]  curUser;
227    curUser  =  _activeusers.Select(strExpr);
228    if  (curUser.Length  >0  )
229    {
230     for(int  i  =  0;  i  <  curUser.Length;  i  ++)
231     {
232      curUser[i]["RefreshTime"]=DateTime.Now;
233     }
234    }
235    _activeusers.AcceptChanges();
236   }
237 
238   private ActiveUser SingleUser(string strUserKey,bool byTicket)
239   {
240    strUserKey=strUserKey.Trim();
241    string  strExpr;
242    ActiveUser myuser;
243    strExpr =byTicket ? "Ticket='" + strUserKey +"'" : "UserName='" + strUserKey + "'";
244    DataRow[]  curUser;
245    curUser  =  _activeusers.Select(strExpr);
246    if  (curUser.Length  >0  )
247 {
248     string myTicket=(string)curUser[0]["Ticket"];
249     string myUser=(string)curUser[0]["UserName"];
250     string myName=(string)curUser[0]["TrueName"];
251     string myRoleID=(string)curUser[0]["RoleID"];   
252     DateTime myActiveTime=(DateTime)curUser[0]["ActiveTime"];
253     DateTime myRefreshtime=(DateTime)curUser[0]["RefreshTime"];
254     string myClientIP =(string)curUser[0]["ClientIP"];
255     myuser=new ActiveUser(myTicket,myUser,myName,myRoleID,myActiveTime,myRefreshtime,myClientIP); 
256    }
257    else
258    {
259     myuser=new ActiveUser("","","","","");   
260    }
261    return  myuser;
262   }
263 
264   /// <summary>
265   ///按Ticket获取活动用户。
266   /// </summary>
267   public ActiveUser SingleUser_byTicket(string strTicket)
268   {
269    return this.SingleUser(strTicket,true);
270   }
271 
272   /// <summary>
273   ///按UserName获取活动用户。
274   /// </summary>
275   public ActiveUser SingleUser_byUserName(string strUserName)
276   {
277    return this.SingleUser(strUserName,false);
278   }
279 
280   /// <summary>
281   ///按Ticket判断用户是否在线。
282   /// </summary>
283   public bool IsOnline_byTicket(string strTicket)
284   {
285    return (bool)(this.SingleUser(strTicket,true).UserName!="");
286   }
287 
288   /// <summary>
289   ///按UserName判断用户是否在线。
290   /// </summary>
291   public bool IsOnline_byUserName(string strUserName)
292   {
293    return (bool)(this.SingleUser(strUserName,false).UserName!="");
294   }
295 }
296 
297 
298 3、 新建一个继承自PlaceHolder名为Refresh的类,执行更新自动刷新时间操作。
299  
300 
301 /// <summary>
302  /// Refresh 执行更新自动刷新时间操作。
303  /// </summary>
304  public class Refresh: PlaceHolder
305  {
306   /// <summary>
307   /// 设置存储Ticket的Session名称,默认为Ticket。
308   /// </summary>
309   public virtual string SessionName
310   {
311    get{
312     object obj1 = this.ViewState["SessionName"];
313     if (obj1 != null){ return ((string) obj1).Trim(); }
314     return "Ticket";
315    }
316    set{
317     this.ViewState["SessionName"= value;
318    }
319   }
320 
321   protected override void Render(HtmlTextWriter writer)
322   {
323    string myTicket=(string)this.Page.Session[this.SessionName];
324    if(myTicket!=null)
325    {  
326     PassPort myPass = new PassPort();
327     myPass.RefreshTime(myTicket);
328     writer.Write("OK:"+DateTime.Now.ToString());
329    }
330    else{
331     writer.Write("Sorry:"+DateTime.Now.ToString());
332    }
333    base.Render(writer);
334  }
335 }
336 
337 4、 新建一个继承自PlaceHolder名为Script的类,生成执行xmlhttp的js脚本。。
338 
339 
340 /// <summary>
341  /// Script 生成执行xmlhttp的js脚本。
342  /// </summary>
343  public class Script: PlaceHolder
344  {
345   /// <summary>
346   /// 设置js自动刷新的间隔时间,默认为25秒。
347   /// </summary>
348   public virtual int RefreshTime
349   {
350    get
351    {
352     object obj1 = this.ViewState["RefreshTime"];
353     if (obj1 != null){return int.Parse(((string) obj1).Trim());}
354     return 25;
355    }
356    set
357    {   
358     this.ViewState["RefreshTime"= value;
359    }
360   }
361 
362   protected override void Render(HtmlTextWriter writer)
363   {
364    //从web.config中读取xmlhttp的访问地址
365    string refreshUrl=(string)ConfigurationSettings.AppSettings["refreshUrl"];
366    string scriptString = @" <script language=""JavaScript"">"+writer.NewLine;
367    scriptString += @"  window.attachEvent(""onload"", "+this.ClientID+@"_postRefresh);"+writer.NewLine;
368    scriptString += @"  var "+this.ClientID+@"_xmlhttp=null;"+writer.NewLine;
369    scriptString += @"  function "+this.ClientID+@"_postRefresh(){"+writer.NewLine;
370    scriptString += @"   var "+this.ClientID+@"_xmlhttp = new ActiveXObject(""Msxml2.XMLHTTP"");"+writer.NewLine;
371    scriptString += @"   "+this.ClientID+@"_xmlhttp.Open(""POST"", """+refreshUrl+@""", false);"+writer.NewLine;
372    scriptString += @"   "+this.ClientID+@"_xmlhttp.Send();"+writer.NewLine;
373    scriptString += @"   var refreshStr= "+this.ClientID+@"_xmlhttp.responseText;"+writer.NewLine;
374    
375    scriptString += @"   try {"+writer.NewLine;
376    scriptString += @"    var refreshStr2=refreshStr;"+writer.NewLine;
377    //scriptString += @"    alert(refreshStr2);"+writer.NewLine;
378    scriptString += @"   }"+writer.NewLine;
379    scriptString += @"   catch(e) {}"+writer.NewLine;
380    scriptString += @"   setTimeout("""+this.ClientID+@"_postRefresh()"","+this.RefreshTime.ToString()+@"000);"+writer.NewLine;
381    scriptString += @"  }"+writer.NewLine;
382    scriptString += @"<";
383    scriptString += @"/";
384    scriptString += @"script>"+writer.NewLine;
385 
386    writer.Write(writer.NewLine);
387    writer.Write(scriptString);
388    writer.Write(writer.NewLine);
389    base.Render(writer);
390   }
391  }
392 
393 
394 注意以上四个类同属于一个名为OnlineUser的工程,他们的命名空间为OnlineUser,编译生成一个dll。
395 
396  
397 
398 
399 ===============================================
400 
401  
402 
403 下面我简单介绍一下调用方法:
404 
405 1、 新建一个名为OnlineUserDemo的asp.net web应用程序
406 2、 在vs的工具箱选项卡上右击,选择[添加/移除项],浏览定位到OnlineUser.dll,确定即可把Refresh 和Script添加到工具箱。
407 3、 把自动生成的WebForm1.aspx删除,并设置web.config
408 <appSettings>
409    <add key="ActiveTimeout" value="30" />
410    <add key="RefreshTimeout" value="1" />
411    <add key="refreshUrl" value="refresh.aspx" />
412  </appSettings>
413 4、添加一个名为Online.aspx的web窗体,给该窗体添加一个Script控件,一个DataGrid控件(id为DataGrid1),两个 HyperLink控件(分别链接到login.aspx和logout.aspx,text属性分别设置为“登陆”和“注销”),调整好四个控件的位置,转到codebehind,在Page_Load中加入如下代码:
414 string myTicket=(string)this.Page.Session["Ticket"];
415    if(myTicket!=null)
416    {
417     OnlineUser.PassPort myPassPort= new OnlineUser.PassPort();
418     if(myPassPort.IsOnline_byTicket(this.Session["Ticket"].ToString()))
419     {
420      myPassPort.ActiveTime(this.Session["Ticket"].ToString());
421      DataGrid1.DataSource=myPassPort.ActiveUsers;
422      DataGrid1.DataBind();
423     }
424     else{
425      //若在线用户列表中找不到当前用户,则定向到注销页面
426      Response.Redirect("Logout.aspx");
427     }
428    }
429    else{
430     Response.Redirect("Login.aspx");
431    }
432 5、添加一个名为login.aspx的web窗体,给该窗体添加一个label控件(id为Label1),设置text属性为“输入一个用户名”,再添加一个textbox控件(id为TextBox1)和一个button控件(id为Button1),调整好他们的位置,双击Button1控件转到 codebehind,为Button1的Click事件加入如下代码:
433 if(TextBox1.Text.Trim()=="")
434    {
435     //不能为空
436     String scriptString = @"<script language=JavaScript>";
437     scriptString += @"alert(""输入一个用户名\n"");";
438     scriptString += @"history.go(-1);";
439     scriptString += @"<";
440     scriptString += @"/";
441     scriptString += @"script>";
442     if(!this.Page.IsStartupScriptRegistered("Startup"))
443      this.Page.RegisterStartupScript("Startup", scriptString);
444    }
445    else{
446     OnlineUser.PassPort myPassPort= new OnlineUser.PassPort();
447     string myTicket=DateTime.Now.ToString("yyyyMMddHHmmss");
448     string myUser=TextBox1.Text.Trim();
449     string myClintIP=this.Request.UserHostAddress;
450     this.Session["Ticket"]=myTicket;
451     OnlineUser.ActiveUser myActiveUser=new OnlineUser.ActiveUser(myTicket,myUser,myUser,"test",myClintIP);
452     myPassPort.Login(myActiveUser,true);
453     Response.Redirect("Online.aspx");
454    }
455 6、 添加一个名为logout.aspx的web窗体,给该窗体添加一个HyperLink控件,指向login.aspx,text属性设置为“重登陆”转到codebehind,在Page_Load中加入如下代码:
456 OnlineUser.PassPort myPassPort= new OnlineUser.PassPort();
457   myPassPort.Logout(this.Session["Ticket"].ToString());
458  this.Session["Ticket"]="";
459 
460 7、 添加一个名为Refresh.txt的文本文件,设置其内容为:
461 <%@ Register TagPrefix="cc2" Namespace="OnlineUser" Assembly="OnlineUser" %>
462 <%@ Page %>
463 <cc2:Refresh id="myRefresh" runat="server"></cc2:Refresh>
464 把Refresh.txt改名为Refresh.aspx
465 
466 8、 编译生成工程。
467 
468 ===============================================
469 
470 
471 下面进行功能测试:
472 
473 1、 打开浏览器,在地址栏输入
474 http://你机器的IP地址/onlineuserdemo/Login.aspx
475 2、 输入一个用户名(假设是test1)登陆,自动转到online.aspx页面
476 3、 找同网段的另外一台机器(设你的机器为a,这台机器为b),重复执行第一步。
477 4、 输入一个用户名(假设是test2)登陆,自动转到online.aspx页面
478 5、 在b机器不断刷新online.aspx,若发现test1用户RefreshTime每过25秒自动更新一次而ActiveTime不变(这个时候a机器不要刷新页面啊),则证明a机器的自动刷新生效。
479 6、 在a机器不断刷新online.aspx,若发现test2用户RefreshTime每过25秒自动更新一次而ActiveTime不变(这个时候b机器不要刷新页面啊),则证明b机器的自动刷新生效。
480 7、 直接关闭一台机器(假设是a)上的online.aspx浏览窗口,在另一台机器(就是b啦)上刷新online.aspx,若发现1分钟后test1掉线在线用户只剩下test2,证明通过_refreshTimeout清除在线用户成功。
481 8、 若5、6、7三步正常,则大功告成,否则就再调试调试~~
482 
483 
484