[Summary] online user list statistics!

Source: Internet
Author: User

1. Implementation of Online User List
In the ASP era, the common practice of displaying the online user list of a website is to modify the following functions in the global. Asa file: application_start, session_start, and session_end. In the ASP. NET era, I still do this. However, you must pay attention to many issues. First, let's take a look at the simplestCodeImplementation:

Protected void application_start (Object sender, eventargs E)
{
Application. Lock ();

Application ["onlineusers"] = NULL;

Application. Unlock ();
}

Protected void session_start (Object sender, eventargs E)
{
Application. Lock ();

If (application ["onlineusers"] = NULL)
Application ["onlineusers"] = new hashtable ();

Hashtable onlineusershash = (hashtable) application ["onlineusers"];
Onlineusershash. Add (request. userhostaddress, request. Cookies ["username"]. value );

Application. Unlock ();
}

Protected void session_end (Object sender, eventargs E)
{
Hashtable onlineusershash = (hashtable) application ["onlineusers"];
Onlineusershash. Remove (request. userhostaddress );
}

This is a simple code that records the list of online users. Is it easy? You can upload it to the server! If you see that your user name has already appeared in the list like me, you will be excited to tell many netizens that the online user list display function is very simple, if you shut down the machine and go to bed, you will be surprised the next morning! There will be countless names in the online user list on your website, and you will know that those people are not online at all... Oh, it's a disaster!AlgorithmThere are no mistakes in thinking, but they produce incorrect results. Why? Although it is a small function, but it hides a lot of xuanjicang, it depends on whether you can unlock...
First of all, I must be certain that using a data structure such as hashtable to store the name of online users is indeed a good choice. The primary key uses the user's IP address, and the primary key value stores the user name. Because the IP address in the network is unique, it is used as the primary key. The cause of the above error is that in the session_end function, hashtable does not delete the primary key ?!
I think all beginners will, like me, ask: Since the IP address is unique throughout the network, why cannot I delete the key in hashtable? The answer is: hashtable does not find the primary key name, that is, the user's IP Address: request. userhostaddress! This sounds a joke. How can I not find the user IP address? As long as the user logs on to the Internet, there must be an IP address! Why can't it be found?
I will tell you the reason is: the user has not logged on to the Internet at all!
What is online or offline? I think you should be dizzy now... However, after reading the legend below, I think you will understand it...
If you think it is a little small, you can adjust the display ratio (word Menu à view à display ratio ).

 

In the left figure, assume that a user first logs on to the bincess forum and then goes to the wadelau.org (wadelau.net) website. However, he has not been disconnected and has been on the Internet. When the afritxia.net server ends the user's session, it will call:

Protected void session_end (Object sender, eventargs E)
{
Hashtable onlineusershash = (hashtable) application ["onlineusers"];
Onlineusershash. Remove (request. userhostaddress );
}

To clear the user name in the online user list. This is correct!
The figure on the right shows that the user has disconnected from the internet before the afritxia.net server ends the user's session. What will happen when the server obtains the user's IP address? I do not know what the result will be, but in short, it is certainly not the result we want, nor will it appear in the primary key name in the onlineusershash data structure.

Because the primary key name cannot be found, onlineusershash cannot remove the corresponding value, therefore, the offline user name is displayed in the online user list (this is called botnet ).

As long as you know the problem, you can come up with a solution. Unfortunately, this problem has been discovered. Then the countermeasures to solve it will soon be developed. In the new algorithm, sessionid is used as the primary key to record user logon information. But there are still many issues to be aware! For example, in an open IE browser, the server will allocate a sessionid to it, but in a new IE browser, the server will still allocate a sessionid to it. This means that the server assigns multiple sessions to the same user, PC, and IP address. Is ie too powerful to request the server ?! Because an open IE browser is a process in the computer, it is natural for the server to assign a session to a process on the client. If myie is used, it is an MDIProgramNo matter how many sub-windows are opened, the sub-Windows belong to only one process. Therefore, for myie, ASP. NET only gives it a session. Note! This is also the reason why there are 0 online users in myie, although you are still online. There is another problem, for example, a user just logged on to bincess and went offline due to line failure. But it wasn't long before he came back, and his cookie had not expired yet, but the IP address and sessionid all changed. If you only want to use sessionid to record the online user list, a user name may be embarrassed twice. The new algorithm is described as follows:

 

Sessionid_1 and sessionid_2 in indicate that username_1 has enabled two ie forms.
Create two hash table structures: onlineusershash and onlineusers_sessioniphash. When a user accesses bincess, A sessionid is assigned to the user. Create a one-to-one correspondence between the IP address and the user name. If the user opens a new window, check whether the user's IP address or user name has already appeared in onlineusershash? If yes, point the new sessionid to the existing IP address. When a session ends, the sessionid is removed from onlineusers_sessioniphash. Determine whether there are other sessionids pointing to this IP address. If not, remove the user name from the online user list. The client situation is quite complex and must be fully considered. The code for the new algorithm is as follows:

// In the global. asax. CS File
//
// Primary key name of the online user list
Public const string key_onlineusers = "onlineusers ";
// Primary key name of the session table in the online user list
Public const string key_onlineusers_sessionip = "onlineusers_sessionip ";

Protected void application_start (Object sender, eventargs E)
{
Application. Lock ();

Application [key_onlineusers] = NULL;
Application [key_onlineusers_sessionip] = NULL; // the user's sessionid corresponds to the IP address.

Application. Unlock ();
}
Protected void session_start (Object sender, eventargs E)
{
Application. Lock ();

/*...*/

Hashtable onlineusershash = (hashtable) application [key_onlineusers];
Hashtable onlineuserssessioniphash = (hashtable) application [key_onlineusers_sessionip];

If (visitor. current. isguest) // if the user is a guest
{< br> If (onlineusershash. containskey (request. userhostaddress)
{< br> onlineusershash [request. userhostaddress] = "";
}< br> else
{< br> onlineusershash. add (request. userhostaddress, "");
}< BR >}< br> else
{< br> If (! Onlineusershash. containskey (request. userhostaddress)
&&! Onlineusershash. containsvalue (visitor. current. username)
{< br> // if the user's IP address and user name cannot be found in the list,
onlineusershash will be added to the online user list. add (request. userhostaddress, request. cookies ["username"]. value);
}< br> else if (onlineusershash. containsvalue (request. cookies ["username"]. value)
{< br> // if the user's cookie information can be found, update (delete and then add) IP address of an online user
// Description: The user may have logged on to the system shortly after the logon due to a line failure, disconnect and dial again
// when the user returns to the website, the cookie has not expired, but the IP address has changed
string username = request. cookies ["username"]. value;

Foreach (Object key in onlineusershash. Keys)
{
If (string) onlineusershash [Key]). Equals (username ))
{
// Delete the IP address that the user just used
Onlineusershash. Remove (key );
Break;
}
}

// Add an online user
Onlineusershash. Add (request. userhostaddress, request. Cookies ["username"]. value );
}
Else if (onlineusershash. containskey (request. userhostaddress ))
{
// If the user's IP address can be found, the name of the online user is updated.
//
// Note: After logging on, log off and log on again. It may be to change the user name.
Onlineusershash [request. userhostaddress] = request. Cookies ["username"]. value;
}
}

// Maps the user's IP address and sessionid
If (! Onlineuserssessioniphash. containskey (session. sessionid ))
Onlineuserssessioniphash. Add (session. sessionid, request. userhostaddress );

Application. Unlock ();
}

Protected void session_end (Object sender, eventargs E)
{
Application. Lock ();

If (application [key_onlineusers]! = NULL)
{
Hashtable onlineusershash = (hashtable) application [key_onlineusers];
Hashtable onlineuserssessioniphash = (hashtable) application [key_onlineusers_sessionip];

// Obtain the user's IP address
String IP = (string) onlineuserssessioniphash [session. sessionid];

// Remove the user's IP address
Onlineuserssessioniphash. Remove (session. sessionid );

// If no session points to this IP address, it indicates that the user has indeed left the website.
// The user name can be deleted.
If (! Onlineuserssessioniphash. containsvalue (IP ))
Onlineusershash. Remove (IP );
}

Application. Unlock ();
}

There are many other algorithms for online user list, but most of them only need databases. A netizen on csdn wrote a more accurate algorithm, which is achieved by recording the time of each user's last activity to regularly and constantly update the new dataset. My algorithm is another way of thinking!

After reading yangzixp (Yangzi (Sichuan Bazhong), the principle is basically the same. The difference is that you use forms authentication and can improve it. Each time application_authenticaterequest checks and deletes the expired user, it must have been too frequent. Use timer instead.

In general, it is easy to calculate the number of online users. However, to make an online list and save the user's access logs requires a lot of system resources, it is hard to say whether it is cost-effective (I only read the requirement documents, regardless of the other ...);

The ihttpmodule method used previously is also good. I learned a trick every time I used it...

Thanks to boss Si for your help. Let's just scatter it ~

Using system;
Using system. componentmodel;
Using system. Web;
Using system. Web. sessionstate;
Using system. Data;
Using system. Data. oledb;

Namespace xsexam
{
/// <Summary>
/// Summary of Global.
/// </Summary>
Public class Global: system. Web. httpapplication
{
Private Static system. Threading. Timer timer;
Private const int interval = 1000*60*10; // check the time interval between online users

/// <Summary>
/// Required designer variables.
/// </Summary>
Private system. componentmodel. icontainer components = NULL;

Public global ()
{
Initializecomponent ();
}

Protected void application_start (Object sender, eventargs E)
{
If (timer = NULL)
Timer = new system. Threading. Timer (new system. Threading. timercallback (scheduledworkcallback ),
Sender, 0, interval );

Datatable usertable = new datatable ();
Usertable. Columns. Add ("userid"); // user ID
Usertable. Columns. Add ("username"); // User Name
Usertable. Columns. Add ("firstrequesttime"); // time of the first request
Usertable. Columns. Add ("lastrequesttime"); // time of the last request
Usertable. Columns. Add ("clientip ");//
Usertable. Columns. Add ("clientname ");//
Usertable. Columns. Add ("clientagent ");//
// Usertable. Columns. Add ("lastrequestpath"); // The Last accessed page

Usertable. primarykey = new datacolumn [] {usertable. Columns [0]};
Usertable. acceptchanges ();

Application. Lock ();
Application ["useronline"] = usertable;
Application. Unlock ();
}
 
Protected void session_start (Object sender, eventargs E)
{

}

Protected void application_beginrequest (Object sender, eventargs E)
{

}

Protected void application_endrequest (Object sender, eventargs E)
{

}

Protected void application_acquirerequeststate (Object sender, eventargs E)
{
Httpapplication Mapp = (httpapplication) sender;
If (MAPP. Context. Session = NULL) return;
If (MAPP. Context. session ["userid"] = NULL) return;
String userid = Mapp. Context. session ["userid"]. tostring ();

Datatable usertable = (datatable) application ["useronline"];
Datarow currow = usertable. Rows. Find (new object [] {userid });
If (currow! = NULL)
{
This. getdatarowfromhttpapp (MAPP, ref currow );
}
Else
{
Datarow newrow = usertable. newrow ();
This. getdatarowfromhttpapp (MAPP, ref newrow );
Usertable. Rows. Add (newrow );
}
Usertable. acceptchanges ();

Application. Lock ();
Application ["useronline"] = usertable;
Application. Unlock ();

}

Protected void application_authenticaterequest (Object sender, eventargs E)
{

}

Protected void application_error (Object sender, eventargs E)
{

}


Protected void session_end (Object sender, eventargs E)
{

}

Protected void application_end (Object sender, eventargs E)
{

}

# Code generated by region web Form Designer
/// <Summary>
/// The designer supports the required methods-do not use the code editor to modify
/// Content of this method.
/// </Summary>
Private void initializecomponent ()
{
This. components = new system. componentmodel. Container ();

}
# Endregion

Private void getdatarowfromhttpapp (httpapplication MAPP, ref datarow mrow)
{
If (MAPP. Context. Session = NULL) return;
If (MAPP. Context. session ["userid"] = NULL | Mapp. Context. session ["username"] = NULL) return;
String userid = Mapp. Context. session ["userid"]. tostring ();
String username = Mapp. Context. session ["username"]. tostring ();
// String requestpath = Mapp. Request. path;

If (mrow ["userid"]. tostring (). Length <1)
{
Mrow ["userid"] = userid;
Mrow ["username"] = username;
Mrow ["firstrequesttime"] = system. datetime. now;
Mrow ["clientip"] = Mapp. Context. Request. userhostaddress;
Mrow ["clientname"] = Mapp. Context. Request. userhostname;
Mrow ["clientagent"] = Mapp. Context. Request. useragent;
}

Mrow ["lastrequesttime"] = system. datetime. now;
// Mrow ["lastrequestpath"] = requestpath;

}

Private void scheduledworkcallback (Object sender)
{
String filter = "convert (lastrequesttime, 'System. datetime ') <convert (' "+ system. datetime. now. addseconds (-integer/1000 ). tostring () + "', 'System. datetime ')";
Datatable usertable = (datatable) application ["useronline"];
Datarow [] lineoutusers = usertable. Select (filter );
For (INT I = 0; I <lineoutusers. length; I ++)
{
Datarow currow = lineoutusers [I];

// Save to database
Xsstudio. Database DB = new xsstudio. Database ();
Currow. Delete ();

}
Usertable. acceptchanges ();

Application. Lock ();
Application ["useronline"] = usertable;
Application. Unlock ();
}


}
}

According to the boss's suggestion, the solution is as follows:
Use ihttpmodule for extra points
First, create the class mymodule that implements the ihttpmodule interface:
Using system;
Using system. Web;
Using system. Data;

Namespace test2004_5_13
{

Public class mymodule: ihttpmodule
{

Public void Init (httpapplication Application)
{
Application. acquirerequeststate + = (New

Eventhandler (this. application_acquirerequeststate ));
}

Private void application_acquirerequeststate (Object source,

Eventargs E)

{

Httpapplication mapplication = (httpapplication) source;

Httpresponse response = mapplication. Context. response;

Datatable dt = NULL;
If (mapplication. Context. application ["useronline"]! = NULL)
{
Dt = (datatable) mapplication. Context. application ["useronline"];
}
Else
{
Dt = new datatable ();
DT. Columns. Add ("username ");
DT. Columns. Add ("firstloadtime ");
DT. Columns. Add ("lastloadtime ");
}

// Add the current user to the online user list
If (mapplication. Context. session! = NULL)
{
If (mapplication. Context. session ["userid"]! = NULL)
{
String username = mapplication. Context. session ["userid"]. tostring ();
Datarow [] rows = DT. Select ("username = '" + username + "'");
If (rows. length> 0)
Rows [0] [2] = system. datetime. Now. tostring ();
Else
DT. Rows. Add (new object [] {username, system. datetime. Now. tostring (), system. datetime. Now. tostring ()});
}
}
DT. acceptchanges ();

Mapplication. Context. application ["useronline"] = DT;

Response. Write ("beginning of request" + dt. Rows. Count. tostring ());
}

Public void dispose ()

{

}

}

}
2) Register in Web. config
<Httpmodules>
<Add type = "test2004_5_13.mymodule, test2004_5_13" name = "mymodule"/>
</Httpmodules>

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.