ASP.NET에서 전역 변수를 사용 현재 접속자 리스트 구현
웹 기반의 응용프로그램을 작성하다 보면 한 사이트에 로그인한 사용자들 끼리 메시지를 주고 받는다거나 현재 접속한 사용자가 누구인지 알고 싶은 경우가 있습니다.
물론 웹 환경 자체가 비연결 지향이라는 점 때문에 이러한 부분의 구현이 까다로운 게 사실입니다.
몇몇 웹 서버 엔진들에서는 접속로그 및 현재 사용자들의 정보에 관해 자세한 정보를 제공하는 걸로 알려져 있지만 보통의 웹 서버(IIS)가 개발환경의 주 무대가 되므로 이러한 선택은 제외하고 생각하겠습니다.
소켓 프로그램처럼(예를 들면 MSN의 현재 로그인한 사용자 목록 보여주기 정도) 대단히 정밀한 계측을 피하는 대신 거의 비슷한 수준의 정보를 전해주는 것이라면 현재 접속자에 대한 정보를 웹 환경에서도 무리 없이 구현이 가능합니다.
순수 웹 프로그래밍만으로 이런 한 기능을 구현하는 것은 몇 가지 해결해야 할 문제들과 운영상의 문제들이 존재하지만 아마도 불만족스럽지는 않을 것 이라 생각됩니다.
구현하는 데는 여러 가지 방식이 존재 하겠지만 쿠키를 사용하지 않고 세션과 전역변수 만으로 구현하는 것을 예로 들겠습니다.
우선 웹 솔루션 전체에서 사용될 수 있는 Application 전역변수를 이용 해야 합니다.
웹 솔루션 전체에서 Global.asax 파일은 하나이고 이 속에는 몇 가지 기본 이벤트들이 구성되어 있습니다.
대표적인 이벤트는 아래와 같습니다.
protected void Application_Start(Object sender, EventArgs e)
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_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)
이벤트의 이름만으로 그 용도를 쉽게 이해하시리라 생각됩니다.
우선 여기서 주목할만한 이벤트는 Application_Start 입니다.
최초로 웹 서버가 응용프로그램을 호출할 때 발생하는 이벤트로 이 부분에 우리는 전역변수를 할당 시켜 줘야 합니다. 현재 사용자 정보가 들어있는 자료구조는 딱 한번 이때 초기화 되어야 할 필요가 있으니깐 말이죠.
현재 사용자는 중복될 수 없으므로 (예를 들어 한 컴퓨터에서 두개의 브라우져를 띄우고 두 번 로그인 할 경우 한 사람이 로그인 한 걸로 판단해야 합니다) 사용자를 쉽게 검색할 수 있는 자료구조에 담는 것이 중요합니다.
그러므로 해쉬 테이블에 사용자리스트를 다고 이 해쉬 테이블을 전역(Application)변수에 할당하는 것이 적당합니다.
다음은 사용자 정보가 들어갈 헤쉬 테이블을 만들고 전역변수에 할당하는 예제입니다.
Global.asax
public static Hashtable now_user=null;
protected void Application_Start(Object sender, EventArgs e)
{
if(now_user==null) now_user=new Hashtable();
Application.Add(“now_user”,now_user);}
…
Application.Add(“now_user”,now_user);
application 변수로 해쉬 테이블을 밀어 넣는 부분입니다.
이렇게 선언되고 나면 웹 응용프로그램 전체에서 이 변수를 참조하는 것이 가능합니다.
그 다음으로는 실제 로그인이 성공하는 페이지에서 이 전역변수에 할당된 헤쉬 테이블 안으로 사용자 정보를 밀어넣는 부분입니다.
if(로그인 성공)
{
System.Collections.Hashtable now_user = (System.Collections.Hashtable)Application.Get(“now_user”);
if(!now_user.ContainsKey(userID))
now_user.Add(userID,userName);
}
로그인이 성공하면 Application에서 할당했던 헤쉬테이블을 들고 옵니다.
System.Collections.Hashtable now_user = (System.Collections.Hashtable)Application.Get(“now_user”);
해쉬 테이블에서 이 사용자가 있는지 여부를 검사한 뒤(컬렉션 객체들 중 키 값 검색에서 헤쉬 테이블이 단연 빛을 발하는 부분) 해당 해쉬 테이블에 사용자 아이디를 키 값으로 사용자이름을 삽입합니다.
if(!now_user.ContainsKey(userID)) now_user.Add(userID,userName);
간단히 사용자 리스트를 얻어오긴 했지만 아직 로그아웃 했을 때의 상황을 고려해야 합니다.
로그아웃 시 현재사용자 리스트에서 사용자를 제거하지 않는다면 만든 의미가 없으므로 사용자 세션이 끝나는 코드에서 로그인한 사용자의 정보를 헤쉬 테이블에서 제거 해야 합니다.
Global.asaxprotected void Session_End(Object sender, EventArgs e)
{
string userId = (string)session[“UserID”]; now_user.Remove(userId);
}
사용자의 세션이 끝날 때 마다 세션 안의 사용자 아이디를 이용 전역 변수로 저장된 해쉬 테이블에서 사용자 정보를 제거합니다.
한가지 문제점은 만약 정상적인 로그아웃을 하지 않은 사용자의 경우 어떻게 처리하는가 하는 것입니다.
로그인 했다가 다른 사이트로 그냥 나가버리는 경우인데 이 경우 정확한 체크가 불가능합니다.
웹 환경이다 보니 언제 이 사람이 다시 웹 서버로 요청을 줄지 알 수 없는 상황이라 지금 당장 없다고 로그아웃 했다고 가정할 수 없는 것입니다.
오히려 대부분의 사용자는 연결지향 소켓의 관점에서는 전부 로그아웃 이라고 볼 수 있습니다.
이 부분에서 정책이 개입하게 되는데 사이트에서는 몇분 동안 응답이 없으면 다른 사이트나 로그아웃 한걸로 간주해서 다시 로그인 시키겠다 머 이런 것입니다.
이 부분은 개발자가 직접 코딩 할 필요 없이 환경설정 파일만으로도 마지막 요청시간과 현재시간을 비교 이후의 것은 짤라 버리는 것이 가능합니다.
아래의 Web.config 는 10분 동안 다시 요청이 없으면 사용자 세션을 죽여 강제 로그아웃 상태로 돌립니다.
<sessionState mode=”InProc” stateConnectionString=”tcpip=127.0.0.1:42424″ sqlConnectionString=”data source=DBSERVER;user id=sa;password=1245″ cookieless=”false” timeout=”10″/>