2011-08-24 19 views
6

Estoy tratando de escribir una aplicación de chat web simple con PHP y AJAX.Hacer un seguimiento de los usuarios que han iniciado sesión en PHP

Necesito ser consciente de todas las sesiones abiertas para que pueda mostrar una lista de usuarios en línea que están disponibles para hablar. También necesito estar al tanto de las salidas porque utilizo "tanto el que envía como el que recibe están fuera de línea" como condición para considerar que una sesión de chat ha finalizado y eliminar los mensajes.

Realizo un seguimiento de los usuarios que inician sesión en una base de datos: agregar una entrada al inicio de sesión y eliminarlo al cerrar la sesión funciona bien, pero no es exhaustivo, ya que hay otras dos maneras de iniciar sesión. fuera:

  • la sesión del lado del servidor caduca después de la inactividad.
  • cookie del lado del cliente se destruye al cerrar el navegador. Parece una mala idea usar algún tipo de AJAX desencadenado (¿qué pasa si el navegador falla o algo así?).

La solución más sencilla parece ser mantener una marca de tiempo de la última actividad. Veo algunos problemas con esto, sin embargo:

  • yo sepa expiración del lado del servidor se basa oportunidad, por lo que no sería exacto (y si me da el tiempo de caducidad 3 minutos equivocado, eso es 3 minutos, donde podría ser un tipo hablando con un usuario sin conexión preguntándose por qué nadie está respondiendo)
  • Tendría que consultar constantemente la base de datos para verificar el tiempo de actividad pasado de todos los usuarios conectados en comparación con la hora actual. No veo cuándo/dónde haría esto de manera eficiente. Parece estúpido hacer esto cada vez que se necesita la lista de usuarios en línea.

Cualquier ayuda apreciada. Estoy codificando esto porque no conozco ningún framework de chat web que pueda integrarse con mi base de datos de usuarios existente, corrígeme si me equivoco.

+0

OK, me di cuenta de que en realidad no necesito intentar estimar la marca de tiempo. Dado que cada usuario está constantemente consultando para buscar nuevos mensajes de todos modos, también puedo actualizar la marca de tiempo cada vez que se realiza la consulta, y considerar toda la marca de tiempo> 20 segundos de usuarios inactivos. Así que ahora solo necesito averiguar la mejor manera para que la base de datos elimine automáticamente las entradas con marcas de tiempo anteriores. – Jonathan

+0

@bfavaretto ¡Muchas gracias por haberlo notado! programadores parece el lugar correcto para preguntar, lo hará. – Jonathan

Respuesta

0

No estoy seguro de si necesita tanto la probabilidad y divisor, pero esto es lo que hago para la gente de automóviles de cierre de sesión:

ini_set('session.gc_maxlifetime',3600); // 1 hour 
ini_set('session.gc_probability',1); // it does garbage cleaning EVERY time 
ini_set('session.gc_divisor',1); // it does garbage cleaning EVERY time 
session_start(); 
+0

Me di cuenta de que esto no es realmente un problema, consulte mi comentario sobre el PO. Sin embargo, tengo que averiguar cómo limpiar las entradas antiguas, y prefiero que la limpieza no se active cada vez que un usuario solicita la lista de usuarios en línea (parece un desperdicio, debe ser centralizado y pasar al lado del servidor). – Jonathan

1

no creo que vas a ser capaz de hacer mucho para mitigar la consulta constante para determinar si los usuarios cerraron el navegador, problemas de conexión a Internet, etc., pero quizás podría hacer que cada cliente haga una solicitud AJAX al servidor cada 5 segundos para actualizar la última actividad y tener su aplicación en el servidor considera que el usuario "cerró sesión" si se saltaron 3-4 solicitudes consecutivas (es decir, su última actividad es> 20 segundos).

En el lado del cliente, podría verificar el último tiempo de actividad cada vez que su cliente envía un mensaje a otro usuario y responder que se había desconectado si eso hubiera sucedido. Si intentaron abrir un chat con otro usuario, también podría hacer una llamada inmediata para verificar su estado. Luego, tal vez pueda verificar el estado de todos los usuarios en la lista de usuarios cada 30 segundos. De esta forma, tu cliente recibe comentarios muy rápidos si la persona con la que está chateando se desconecta inesperadamente.

+0

Estoy de acuerdo con la primera parte, creo que sería más eficiente hacer que la base de datos haga un seguimiento interno de las marcas de tiempo caducadas, ya que no tiene sentido tener 10 usuarios al mismo tiempo haciendo que la base de datos limpie las fechas de vencimiento. ¿Debo usar cron + el cliente mysql para hacer esto, o hay una forma mejor? – Jonathan

+1

Cron está bien, pero mejor ejecutarlo a través de un script PHP que accede a la base de datos, de esa manera será más fácil para usted si desea cambiar el comportamiento más adelante. – Ravi

+0

Estoy de acuerdo con Ravi, cron + un script PHP es el camino a seguir aquí. Supongo que tienes acceso a crontab desde que lo pides, pero si por algún motivo no lo haces, puedes configurar la función "cron de un pobre" que mantendría un registro de la última vez que se había realizado una tarea. ejecutado y ejecutado de nuevo si han pasado $ x segundos, y haz que tu script PHP ejecute esa función en cada solicitud. Es difícil de hacer, y no tan preciso, ya que no se puede garantizar exactamente cuándo se ejecutará la tarea, pero funciona en un apuro. Tuve que hacer eso antes cuando no tenía acceso a crontab ... –

0

La mayoría de los datos que está utilizando actualmente y los datos que necesita se almacenan en la sesión de PHP; simplemente no es obvio cómo derivar la identificación de usuario de la información.

Si cambia a usar un manejador de sesión enlazado a la base de datos, entonces todo se vuelve muy fácil. Tuve un Google rápido, y hay muchos ejemplos por ahí. pero muchos de ellos (p.this one) no verifique el vencimiento al leer la sesión. OTOH, el ejemplo al que me he vinculado muestra cómo agregar el ID de usuario al registro de sesion, que necesitará más adelante. Por lo que la función de controlador de leer sesión debe ser algo como:

read: 
SELECT session_data, username 
FROM sessions 
WHERE session_id=' . session_id() . ' 
AND last_updated>= ' . date('YmdHis', time()-ini_get('session.gc_maxlifetime')) 

Y para obtener toda la sesión iniciada usuarios:

SELECT username 
FROM sessions 
WHERE last_updated>= ' . date('YmdHis', time()-ini_get('session.gc_maxlifetime')) 

... y dejar que el recolector de basura (anulado) sesión automáticamente clara a cabo datos redundantes.

HTH

0

Primero separa tus preocupaciones. En cuanto a la 'lista de usuarios en línea', puede usar la base de datos &, parece que ya se ha dado cuenta. (incluso si alguien no cierra sesión correctamente, mostrar algunos usuarios adicionales en línea no causará mucho daño)

Ahora, para la aplicación de chat, para verificar si un usuario todavía está en línea, deberá usar ajax. Simplemente no hay otra manera. Por supuesto, siempre puede haber un truco, no sé. vea la imagen image cuando responda aquí (stackoverflow). Constantemente verifica si ha pasado el tiempo (& ha escrito algo nuevo) & guarda una copia.

1

Puede invertir su patrón, reemplazando su comportamiento de extracción de Ajax con un sistema de notificación de inserción.

De esta manera puede notificar a los usuarios de su chat en tiempo real de inicio de sesión y cierre de sesión de los nuevos miembros del chat. Nunca hice algo así en la práctica, pero he leído sobre este tipo de tecnología y parece muy interesante para casos como el tuyo.

Es un poco más difícil que el modo Ajax, pero una vez que se implementa la estructura principal puede agregar funcionalidad fácilmente y el rendimiento sería mucho mejor.

Algunos enlaces que encuentran que pueden ser útiles:

Este es un episodio Railscast que se ocupan de una charla Javascript, la aplicación está en los carriles, pero incluso Si no comprende los rieles, debe poder seguirlos para obtener los conceptos básicos: http://railscasts.com/episodes/260-messaging-with-faye

+0

Gracias por esta respuesta: no tenía conocimiento de la existencia de marcos de notificación de inserción para JS, así que ahora tengo algo nuevo con lo que me tengo que familiarizar. :-) –

+0

Fuera de mi alcance por ahora, pero tampoco era consciente de esto, siempre consideré la falta de empuje una gran limitación de AJAX. Genial saber. – Jonathan

0

Parece que está más preocupado por el rendimiento y tiene los detalles de implementación resueltos (en su mayoría). Simplemente cambie el tipo de tabla que maneja las sesiones a 'memoria', esto reducirá el costo de rendimiento de hacer que el DB por cada solicitud sea casi nulo ya que está obteniendo datos directamente de la RAM. Solo asegúrese de eliminar la sesión cada vez que un usuario explicity cierre sesión, o marque al usuario como inactivo.

Pero no importa lo que haga implementando algo que requiera comunicación constante entre el cliente y el servidor nunca se puede hacer perfectamente a través de HTTP. Pero si pones tiempos de espera razonables, etc. funcionará el 99% del tiempo.

0

Llego tarde a esta fiesta, pero déjame dar mis dos centavos.

En este caso particular, no hay necesidad de un sistema de inserción para las notificaciones incorrectas.Tampoco hay necesidad de cron. Permítanme explicar:

Diga A, B y C están en una sala de chat & El navegador B se cuelga, por lo que su sesión expira. En este momento, el servidor cree que B todavía está allí, pero ella no. ¿Cómo se actualiza A & C? Cuando A & C PIDE la actualización. Verifique la última marca de tiempo keepalive de B y descubra que su sesión ha expirado.

Si todo A, B & C se cuelga, entonces esto nunca sucede. Te escucho preguntar. ¿A quien le importa? ¡No hay nadie para ver nuestro error ahora! El único inconveniente es mantener viva su sala de chat, lo que cuesta un poco de espacio en la base de datos. Esto se puede limpiar cuando se crea otra sesión de chat.

Un último GIST:

  1. Mantener marcas de tiempo para la última vez que se toma una acción.
  2. Utilice un evento de usuario para recorrer las marcas de tiempo y sacar la madera muerta.

En el caso de los usuarios, esto sería cerrar la sesión. En el caso de las salas de chat, estas serán las que hayan expirado.

Cuestiones relacionadas