欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

关于用户在线与离线的判断问题!

程序员文章站 2024-01-12 15:31:28
...
首先需求是做一个显示在线用户昵称和在线人数。

然后个人的思路是在用户表里面做一个字段用来标记用户在线(1)或者不在线(0),当用户登录的时候就设置这个字段为1,当用户通过正常渠道(即点击安全退出)退出的时候就设置这个字段为0.这样就显示在线用户的话就可以定时刷新一次,这种情况下功能是没有任何问题的,但是例外情况就是用户不点击安全退出而是直接就关闭浏览器了,那这样这个用户岂不是永远都在线了?所以我的问题是如何处理当用户通过非正常渠道离开之后也能检测到他是否在线。

请大神帮忙~~~~

回复讨论(解决方案)

每个页面中都加入公共js文件,里面的某个js函数负责定时向某php文件(如a.php)发送ajax请求。最后请求时间由a.php每次写入session

比如设定每2分钟发送一次请求。在需要获取用户是否在线的页面上,读出session里的最后请求时间,当前时间减去最后请求时间,若大于2分钟,则用户已离线。

1:楼主的想法比较天马行空,估计是事前没有参照过别人的想法
2:1楼的答案逻辑不过关.20个用户同时访问这个页面?到了2分钟?每个用户发送一个请求到服务器端?服务器要处理多少次?如果你要说你服务器很牛B,好吧!那服务器很牛B!但是还有前提也要让用户这个傻逼一直停留在某个页面长达2分钟?

这个问题网上可以顺手找到很多案例。
如果想采用最轻巧的,可以统计session临时文件数量或其它存储方式的单元数量,来确定当前20分钟内有多少在线。当然,这个时间精确度可以缩小到一分钟(随之而增长的是会话回收机制的消耗)。
无论采取任何方案,这个功能还是对服务器有不少消耗,如果不是很必要,建议放弃。

正确的思路并且不借助memcache等第三方工具的方法是
分析:在线统计难点是在于不存在全局共享的方法
解析办法:
利用文件来保存在线用户的信息,这样对文本的处理实际上还比数据库快很多(php连数据库的时间就已经超过了php读取一个小文本的时间)
文本里保存的格式为数组,格式为

13671927362,//key值为用户uid    value值当用户登陆的时间戳   20313=>13671927363,);

1:当用户登陆时,获取当前时间戳,session记录用户id
2:然后获取文本里的文件,里面保存了在线用户的信息,判断当前uid是否存在这里面,不存在就插入,然后继续保存
3:在线人数获取,就读取文件,然后count出在线人数
4:只要当访问这个文件的时候(不管你是准备统计在线人数,还是有新用户加入),遍历文本里的数据,判断各个用户的时间戳是否小于当前时间戳并超过半小时,如果是,那么就去掉这个用户信息.
实现步骤关键点:
以数组获取文本
$online=require 'xxx.php';
以数组保存文本
$data[1111]=123748492;
file_put_contents('xx.php','


正确的思路并且不借助memcache等第三方工具的方法是
分析:在线统计难点是在于不存在全局共享的方法
解析办法:
利用文件来保存在线用户的信息,这样对文本的处理实际上还比数据库快很多(php连数据库的时间就已经超过了php读取一个小文本的时间)
文本里保存的格式为数组,格式为

PHP code  
 ?  
  
 123456  
  
 <?php return array(   ……

你这个第四步当访问这个文件的时候?那这个文件是我访问的时候还是用户访问的时候?还有就是你说用文本的方式实现在线用户统计,那假如你的那个文件是每当有用户登录的时候就会访问的话,那你再新加入用户的时候判断所有用户加入时候的时间戳和当前这个用户的时间戳比较的话,那这种就会产生好多用户其实在线但是你已经在程序里把他算做是离线了!
那如果你的那个文件是我访问的时候就是我在需要获取在线用户的页面里面定时访问这个文件的时候,那你那个存放用户在线信息的文件更新怎么做?
我看了大家的回复之后也没有一个具体的思路!


function counter_user_online($temp){	
$user_online = "count.txt"; //保存人数的文件,网站根目录下	
touch($user_online);//如果没有此文件,则创建	
$timeout = 120;//120秒内没动作者,认为掉线	
$user_arr = file_get_contents($user_online);	
$user_arr = explode('#',rtrim($user_arr,'#'));	
$temp = array();	
foreach($user_arr as $value){		
$user = explode(",",trim($value));		
if (($user[0] != getenv('REMOTE_ADDR')) && ($user[1] > time())) { 
//如果不是本用户IP并时间没有超时则放入到数组中			
array_push($temp,$user[0].",".$user[1]);		
}	
}	
array_push($temp,getenv('REMOTE_ADDR').",".(time() + ($timeout)).'#'); //保存本用户的信息	
$user_arr = implode("#",$temp);	//写入文件	
$fp = fopen($user_online,"w");	flock($fp,LOCK_EX); //flock() 不能在NFS以及其他的一些网络文件系统中正常工作	
fputs($fp,$user_arr);	
flock($fp,LOCK_UN);	
fclose($fp);	
echo count($temp);}

度娘里找的,你可以加一个字段,判定是否离线,


引用 4 楼 zouhao619 的回复:正确的思路并且不借助memcache等第三方工具的方法是
分析:在线统计难点是在于不存在全局共享的方法
解析办法:
利用文件来保存在线用户的信息,这样对文本的处理实际上还比数据库快很多(php连数据库的时间就已经超过了php读取一个小文本的时间)
文本里保存的格式为数组,格式为

PHP code  
 ?  
  
  
 ……

1:我的是用户访问才触发(你想着,这是渣渣,最好能自动触发.....想一想,用户(包括你自己)想看到在线用户,其实上是已经访问了这个页面了,所以已经触发了这个页面,咳咳,我说的是任何页面都必须有这样的代码,可以参照第5步的方式减少代码冗余)
2:文本里保存的各个的用户以及各个用户操作的时间戳,(如果你觉得这样不好,想更及时一点,也可以选择记录最后一次用户操作页面的时间戳,只是这样会加大服务器的压力,我觉得是没必要的)
3:用户更新时间,实际上我之前说过了.当用户操作页面时,就读取文件,判断用户是否在这个文本里,如果没有就添加当前用户id以及当前用户的时间戳.
4:删除用户时间.当第三步进行的同时,也判断各个用户的时间戳与当前时间戳相差半小时(半小时这个时间可以由你决定最合适的时间)以上的,就删除掉.
5:用户操作每一步都要进行验证判断,读取文本文件,现在一般设计都是采用单入口形式,你可以定义基类,放在构造函数里,这样可以解决代码冗余(每一步都读取文本文件,不要思考压力很大,其实读小文件压力根本不大,当你去访问php页面的时候,实际上也是对这个进行了读操作)

实现流程 我就不讨论了,关于这个存储方法,我倒是建议将数据保存到临时内存表内.当然,这也得考虑你的硬件环境.

这个问题网上可以顺手找到很多案例。
如果想采用最轻巧的,可以统计session临时文件数量或其它存储方式的单元数量,来确定当前20分钟内有多少在线。当然,这个时间精确度可以缩小到一分钟(随之而增长的是会话回收机制的消耗)。
无论采取任何方案,这个功能还是对服务器有不少消耗,如果不是很必要,建议放弃。

我可不可以这样,因为我必须要在数据库里面做一个字段来标志用户是否在线,那么按你这个统计session数量的方法来说,我可以在用户登录的时候用session记录它的id和登录时间,然后设置这个session的过期时间为5个小时,那么我可以每隔20分钟就去遍历一次存放session文件的目录,然后按个儿打开每个session文件,然后分析文件里面的内容获取到用户id和登录时间,然后我把用户的登录时间和当前时间做差如果大于了5个小时(这里是表示限制用户最长能一直在线的时间为5小时)则就把当前id的用户存放在一个数组中,并且删除这个session文件,一直到遍历完所有的文件,将存放过期用户id的数组构造成字符串然后一次性更新数据库。
当然还可能就是用户点击了那个“7天内免登陆”,这样的话我可以在更新之前再加一步,以为我们存cookie的时候用一个固定的前缀和用户id作为名字,那这样我再挨个儿找一遍cookie,将有cookie的id剔除掉,这样的话我就可以很好的实现这个功能了。
那么我也不用在每个页面放一个js文件定时请求服务器了,只需要在哪个显示在线用户的页面里面放一个就可以了。
请问我这种思路有什么问题吗?请指导下,谢谢!

引用 5 楼 BeyondQqiang 的回复:引用 4 楼 zouhao619 的回复:正确的思路并且不借助memcache等第三方工具的方法是
分析:在线统计难点是在于不存在全局共享的方法
解析办法:
利用文件来保存在线用户的信息,这样对文本的处理实际上还比数据库快很多(php连数据库的时间就已经超过了php读取一个小文本的时间)
文本里保存的格式为数组,格式……
请看下9楼我的回复,然后请谈谈你自己的想法,请指教!

实现流程 我就不讨论了,关于这个存储方法,我倒是建议将数据保存到临时内存表内.当然,这也得考虑你的硬件环境.

请看我9楼的回复,请指教!

存入普通文件的关键,是写入时候的资源独占问题。

存入普通文件的关键,是写入时候的资源独占问题。
一语道破

引用 3 楼 dream1206 的回复:这个问题网上可以顺手找到很多案例。
如果想采用最轻巧的,可以统计session临时文件数量或其它存储方式的单元数量,来确定当前20分钟内有多少在线。当然,这个时间精确度可以缩小到一分钟(随之而增长的是会话回收机制的消耗)。
无论采取任何方案,这个功能还是对服务器有不少消耗,如果不是很必要,建议放弃。
我可不可以这样,因为……
不可行!
每次session临时文件是靠sessionId,sessionId不一样,生成临时文件目录都不一样.
我存在的疑问:
1:能够读取临时文件夹的session文件吗?它是否有被加密过?还是纯文本?
2:如果是文本?里面存的就是session的内容?那么那些数组,对象是如何被存入文本的?(数组还可以,对象是怎么存入文本的?)

每次session临时文件是靠sessionId,sessionId不一样,生成临时文件目录都不一样.
我存在的疑问:
1:能够读取临时文件夹的session文件吗?它是否有被加密过?还是纯文本?
2:如果是文本?里面存的就是session的内容?那么那些数组,对象是如何被存入文本的?(数组还可以,对象是怎么存入文本的?)
1、当然可以读取 session 临时文件。你可以在 session.save_path 指定的地方找到他们
2、session 临时文件是纯文本文件。是用简化的序列化格式存储的,php 已然提供了 session 序列化和反序列化的函数。你自己看一下就知道了

你们都在讨论如何存储的问题,其实如何存储并不是主要问题
关键在于“如何识别”,既然一致认为“非正常渠道离开”的检查是需要轮询的。那就把的种方案都弄出来PK一下就是了(假定有一万个用户在线)

引用 3 楼 dream1206 的回复:这个问题网上可以顺手找到很多案例。
如果想采用最轻巧的,可以统计session临时文件数量或其它存储方式的单元数量,来确定当前20分钟内有多少在线。当然,这个时间精确度可以缩小到一分钟(随之而增长的是会话回收机制的消耗)。
无论采取任何方案,这个功能还是对服务器有不少消耗,如果不是很必要,建议放弃。

我可不可以这样,因为……
你不需要去修改你原有的代码,这也是我认为统计session是最轻便的原因。
PHP有GC session机制,它会在一定概率下启动,并清理超过配置项 session.lifetime 的session。这个默认值是21分钟,但是这个误差时间要大,因为不确定在什么时候才能满足概率开始回收过期会话。
你仅仅需要统计session文件夹里有多少个文件而已,不必去一个个的读然后判断。

<?php
$path=session_save_path();
$path || ($path='/tmp');$path .= '/sess_*';echo "当前在线人数: ". count( glob($path) );

终极必杀 写一个客户端...想怎么控制怎么控制.

这种CS行为上 BS的网站还是比较吃力,所以如果你对这个场景确实很重视那么就来个客户端吧...

引用 9 楼 BeyondQqiang 的回复:引用 3 楼 dream1206 的回复:这个问题网上可以顺手找到很多案例。
如果想采用最轻巧的,可以统计session临时文件数量或其它存储方式的单元数量,来确定当前20分钟内有多少在线。当然,这个时间精确度可以缩小到一分钟(随之而增长的是会话回收机制的消耗)。
无论采取任何方案,这个功能还是对服务器有不少消耗,如果不……

好吧,你得自己打开一个session文件,然后发现他们其实是可以被手动读出来的并且目录是可以指定的。

回一个,下班了回来看看

都有着弊端