◇ ASP에러 처리의 처음과 끝

JSP가 갖고 있는 장점중의 하나가 Exception(Error)처리가 뛰어 나다는 것입니다. 철저한 Exception Class를 상속해 가면서 마치

작은 그물에서 큰 그물로 이어가는 에러 처리 기법은 프로그래머를 매우 정신적으로 여유있게 해주는 기능 중에 하나 입니다.

ASP의 경우 3.0으로 업그레이드 되면서 ASPError객체를 제공함으로써 기존의 Err객체의 단점을 개선하기는 했지만 이 역시도

내부서버오류 앞에서는 전혀 무용지물입니다.

아쉽지만 그래도 에러를 잡아 낼 수 있는 방법이 무엇이 있는지 알아 보도록 하겠습니다.

(참고로 자바스크립트 에러는 웹브러우저가 자동으로 에러를 찾아 줍니다.)


1. Response.End를 이용한 에러 잡아 들이기

에러를 잡는 가장 고전적인 방법입니다.

ASP코드의 중간에

Response.Write "여기 까지는 이상이 없습니다."

Response.End

라고 사용하면 에러가 발생되는 라인을 알아 낼 수 있는 방법입니다.

하지만 이 방법은 프로그램의 라인이 많으면 반복해서 사용해야 함으로 효율이 떨어지고 IE의 버퍼에

문제 있는 코드가 있다면 계속 오류 발생하여 버퍼를 다 지우고 IE를 모두 닫았다가 열어야 하는 번거로움이 있습니다.

하지만 위의 방법은 가장 간단하고 별 다른 코드 입력이 없기 때문에 아직도 많이 쓰여지고 있습니다.

특히 SQL문 실행 과정에서 에러가 나는 부분은 아래처럼 함으로 확인 할 수 있습니다.

esponse.Write sql

Response.end


2. Err객체를 이용한 에러 처리하기

아래와 같이 에러가 있는 파일을 작성합니다.

Err.asp로 저장하고 불러 옵니다.

<HTML><BODY>
<%
Dim su1, su2, hap, cha, gob, div
su1=100 : su2=0

hap=su1+su2 : cha = su1-su2 : gob = su1 * su2 : div = su1 / su2
Response.Write "두수의 더하기 : " & hap & "<BR>"
Response.Write "두수의 빼기: " & cha & "<BR>"
Response.Write "두수의 곱하기 : " & gob & "<BR>"
Response.Write "두수의 나누기 : " & div & "<BR>"
%>
</BODY></HTML>

위의 에러의 경우 전 두대의 컴퓨터로 테스트를 해보았습니다.

서버상에서의 결과 화면

다른 클라이언트에서의 결과 화면 입니다.

같은 에러에 대해서 다른 화면이 보이고 있습니다. 어떤 때는 에러의 원인이 보이고 어떤 때에는

골치아픈 HTTP 500 내부 서버 오류가 나오고 있습니다. IIS를 정지하고 버퍼를 지우고 다 해보았지만 결과는 같았습니다.

위의 경우 해결 방법은 Response.end를 중간 중간에 심어서 테스트 하는 1번의 방법을 이용하면 찾아 낼 수 있습니다.

이런 상황이 계속 되면 성질 급한 사람은 포기를 하던 아니면 오기로 매달리는 겁니다.밤 새도록...

이번에는 Err객체를 이용해서 에러를 잡아 보겠습니다. 아래의 소스처럼 수정하고 실행시킵니다.

Err2.asp로 저장하고 불러 옵니다.

<%
Option Explicit
On Error Resume Next
%>
<HTML><BODY>
<%
Dim su1, su2, hap, div

su1=100 : su2=0 : hap=su1+su2 : div = su1 / su2

Response.Write "두수의 더하기 : " & hap & "<BR>"
Response.Write "두수의 나누기 : " & div & "<BR>"

If Err.Number > 0 then
Response.Write "에러가 있습니다."
Err.Clear
else
Response.Write "에러가 없습니다."
End if

%>

</BODY></HTML>

아래는 2대의 컴퓨터의 결과 화면입니다. 자세히 원인은 모르지만 페이지 자체적으로 Err객체는 에러를 알아 내고 있습니다.

Option Explicit 는 변수 선언 확인문 입니다. 선언되지 않은 변수는 사용할 수 없어서 변수로 인한 오류를 막을 수 있는좋은 방법입니다.

On Error Resume Next문은 에러가 나도 계속 진행하라는 선언문입니다. 그래야 에러 원인을 알 수 있습니다.

Err.Number는 에러가 난 갯수를 갖고 있는 객체 입니다. 따라서 에러가 발생하면 에러 갯수로 에러를 알 수 있습니다.

Err.Clear는 반드시 선언해야 합니다. 에러를 Err객체 목록에서 지우는 역활을 합니다.

아래와 같이 소스를 수정하고 테스트 합니다.

Err3.asp로 저장하고 불러 옵니다.

<%
Option Explicit
On Error Resume Next
%>
<HTML><BODY>
<%
Dim su1, su2, hap, div

su1=100 : su2=0 : hap=su1+su2 : div = su1 / su2

Response.Write "두수의 더하기 : " & hap & "<BR>"
Response.Write "두수의 나누기 : " & div & "<BR>"

If Err.Number > 0 then
Response.Write "에러가 있습니다.<BR><BR>"
Response.Write "ASP에 지정된 에러 번호:" & Err.Number & "<BR>"
Response.Write "에러 원인 : " & Err.Description & "<BR>"
Response.Write "에러를 발생 시킨 객체 :" & Err.Source & "<BR>"
Err.Clear
else
Response.Write "에러가 없습니다.<BR>"
End if

%>

</BODY></HTML>

결과는 아래와 같습니다. 좀더 자세한 결과가 출력 되었습니다.

Err객체의 경우 어느 라인에서 에러가 났는지 알아낼 방법이 없습니다.


3. IE의 기능을 이용한 에러 잡기(HTTP 500 내부서버 오류 잡아냄)

아래처럼 소스를 작성하고 IE에서 확인 합니다. ("%>" ASP표식이 빠져있습니다.)

Err4.asp로 저장하고 불러 옵니다.

<HTML><BODY>
<%
Response.clear
Response.Write "A" & "<BR>"
Response.Write "B" & "<BR>"


</BODY></HTML>

아래는 결과 화면입니다. 역시 HTTP 500 - 내부 서버 오류가 뜹니다.

IE를 열고 [도구]메뉴의 [인터넷 옵션]을 클릭합니다.

[고급]탭의 [HTTP 오류 메시지 표시] 체크를 풀어 줍니다.

[확인]을 누르고 페이지를 다시 불러 온 결과입니다. 내부 서버 오류의 원인이 보이고 있습니다.

이 방법은 DB관련 내부서버 오류도 잡아 내는 기능을 갖고 있습니다.

위의 방법 중에서 3번이 가장 정확히 HTTP 500 - 내부 서버 오류를 찾아 냈습니다. 3번의 방법은 한번만 설정해 두면 편리할 것입니다.

평상시에 Option Explicit문을 선언하는 습관을 갖으셨으면 좋겠습니다.

그리고 Err객체도 완전한건 아니지만 많은 도움이 될 것입니다.


4. IIS에 사용자가 에러 페이지 만들어 추가하기

1. 아래의 내용을 error500.asp 로 해서 IIS 기본 웹사이트에 등록할 경우 c:\winnt\Help\iisHelp\common폴더에 저장합니다.


<%Set objError = Server.GetLastError%>

<html>
<body bgcolor=#fcffef>
<h4>에러 이름 : 500 내부 서버 오류입니다.</h4>
<hr>
ASPError.Number : 0x<%= Hex(objError.Number) %><br>
<font color="red">
ASPError.Source : <%= Server.HTMLEncode(objError.Source) %><br>
</font>
ASPError.Category : <%= objError.Category %><br>
ASPError.File : <%= objError.File %><br>
<font color="blue">
ASPError.Line : <%= objError.Line %><br>
ASPError.Column : <%= objError.Column %><br>
</font>
ASPError.Description : <%= objError.Description %><br>
<hr>
<input type="submit" value="다시 읽기" onclick="location.reload()">
<input type="submit" value="돌아가기" onclick="history.back()">

</body>
</html>

 

2. 에러를 적용하려는 프로젝트를 선택하고 [등록정보]로 들어갑니다.
 


3. [사용자 정의 오류]탭을 선택하고 500;100을 선택하고 [등록 정보 편집] 버튼을 클릭합니다.
 


4. 메시지 형식을 [URL]로 바꿉니다.
 


5. 메시지 형식을 URL로 지정하고 URL은 같은 사이트의 가상 디렉토리를 지정합니다.
    실제로 저는 기본 웹사이트를 사용함으로 IIS에서 열어보면
[/IISHelp/common/]이라는 폴더를 발견할 수 있습니다.
    이 가상 디렉토리는 실제로
c:\winnt\Help\iisHelp\common로 매핑 되어 있습니다.
 


6. 정상적으로 등록된 것이 보입니다.
 


7. 잘못된 ASP파일을 작성합니다. test.asp로 저장합니다.

<%
option explicit

Dim str

str = "<body>안녕하세요..?"
      & " 반갑습니다."

Response.Write str
%>
 


8. 에러 원인이 자세하게 출력 되었습니다.
 


9. 에러를 수정하고 다시 읽기 버튼을 누르면 결과가 제대로 보입니다.

수정된 test.asp파일

<%
option explicit

Dim str

str = "<body>안녕하세요..?" _
      & " 반갑습니다."

Response.Write str
%>


10. 정상적으로 출력 되었습니다.
 


2007/11/22 15:00 2007/11/22 15:00

약간의 꽁수로 자신의 홈페이지에 방문하는 분들에게 내 홈의 아이콘을
바탕화면에 설치되도록 할수 있습니다.
이미 알고계신분들고 계시겠지요..
엑티브엑스를 이용해서 만들려면 프로그래밍 못하는 사람들은 어림도 없죠..
아래 소스를 인덱스파일에 넣어주시면 해결됩니다.

<head> 와 </head> 사이에 넣어주셔야합니다.

<script language='JavaScript' SRC='http://inlive.co.kr/js/ShortCut.js'></script>
<script language='JavaScript'>
  MakeShortCut("아이콘제목", "홈페이지주소", "아이콘파일경로");
[ Ex.. MakeShortCut("바로가기","http://demo.webbut.com","http://demo.webbut.com/webbut.ico"); ]
</script>

 

원문 : http://www.nzeo.com/bbs/zboard.php?id=p_etc&page=1&sn1=&divpage=1&sn=off&ss=on&sc=off&select_arrange=hit&desc=desc&no=699

2007/11/22 15:00 2007/11/22 15:00
맨날 게시판 여기저기를 뒤져보면서 남들한테 물어보고 다니다가 제가 처음으로 Tip 이란 것을 올려봅니다.

허접이긴 한데요... 그래도 중복로그인을 어느정도는 차단할 수 있는 것 같기에 제 경험을 올려봅니다.

아니다 싶으면 과감하게 꾸짖어주세요..


맨처음 드리고 싶은 말씀은 중복로그인을 막으려면 일단 ActiveX를 통해서 처리할 수 밖에는 없다는 것을 말씀드리고 싶습니다.

그것은 ASP 에서는 Global.asa 에서 Session_OnEnd 이벤트를 통해서 세션종료를 처리하는데 웹사이트에서 로그아웃을 하지 않고 웹브라우저를 종료했을때는 일단 종료한 시점부터 Session.TimeOut 으로 설정한 시간동안 유저의 이벤트가 없는 것으로 처리해서 그 시간이 지나야만 세션을 종료처리합니다.


따라서 Session.TimeOut 에서 30분으로 설정한다면 30분동안 재접속할때는 그것이 중복로그인인지 정상로그인인지 파악이 안된다는 것이지요.


그래서 저는 ActiveX를 통해서 다음의 두가지 기능을 추가했습니다.



하나는 사용자의 랜카드 mac address를 가져와서 체크하는 것이고요.

다른 하나는 Inet 방식으로 ActiveX에서 웹서버의 특정파일에 POST 방식으로 정보를 보내는 것입니다.


먼저 랜카드 mac address를 가져오는 것입니다.




다음은 모듈부분입니다.

-----------------------

Option Explicit

Option Base 0


Private Declare Function GetNetworkParams Lib "IPHlpApi" (ByRef pFixedInfo As Any, ByRef pOutBufLen As Long) As Long

Private Declare Function GetAdaptersInfo Lib "IPHlpApi" (IpAdapterInfo As Any, pOutBufLen As Long) As Long

Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any, Source As Any, ByVal Length As Long)


Private Const ERROR_BUFFER_OVERFLOW = 111&

Private Const MAX_ADAPTER_NAME_LENGTH As Long = 260

Private Const MAX_ADAPTER_ADDRESS_LENGTH As Long = 8

Private Const MAX_ADAPTER_DESCRIPTION_LENGTH As Long = 132

Private Const DEFAULT_MINIMUM_ENTITIES As Long = 32

Private Const MAX_HOSTNAME_LEN As Long = 128

Private Const MAX_DOMAIN_NAME_LEN As Long = 128

Private Const MAX_SCOPE_ID_LEN As Long = 256

Private Const MIB_IF_TYPE_OTHER As Byte = 1

Private Const MIB_IF_TYPE_ETHERNET As Byte = 6

Private Const MIB_IF_TYPE_TOKENRING As Byte = 9

Private Const MIB_IF_TYPE_FDDI As Byte = 15

Private Const MIB_IF_TYPE_PPP As Byte = 23

Private Const MIB_IF_TYPE_LOOPBACK As Byte = 24

Private Const MIB_IF_TYPE_SLIP As Byte = 28


Private Type typIPStrs

    tNext As Long

    IpAddress As String * 16

    IpMask As String * 16

    Context As Long

End Type


Private Type typFixedInfo

    Hostname As String * 132

    DomainName As String * 132

    CurrentDnsServer As Long

    DnsServerList As typIPStrs

    NodeType As Long

    ScopeId As String * 260

    EnableRouting As Long

    EnableProxy As Long

    EnableDns As Long

End Type


Private Type typIpAdapterInfo

    tNext As Long

    ComboIndex As Long

    AdapterName As String * MAX_ADAPTER_NAME_LENGTH

    Description As String * MAX_ADAPTER_DESCRIPTION_LENGTH

    AddressLength As Long

    Address(MAX_ADAPTER_ADDRESS_LENGTH - 1) As Byte

    Index As Long

    tType As Long

    DhcpEnabled As Long

    CurrentIpAddress As Long

    IpAddressList As typIPStrs

    GatewayList As typIPStrs

    DhcpServer As typIPStrs

    HaveWins As Boolean

    PrimaryWinsServer As typIPStrs

    SecondaryWinsServer As typIPStrs

    LeaseObtained As Long

    LeaseExpires As Long

End Type


Public Type typIPAdapter

    AdapterName As String

    AdapterType As String

    Description As String

    MacAdress As String

    IpAddressCount As Long

    IpAddress() As String

End Type


Public Type typAdapters

    Count As Long

    Item() As typIPAdapter

End Type


'/**  GetIPAdapters

' *     gets the adapters installed on local machine

' *

' *     @returns     typAdapters ,

' */

Public Function GetIPAdapters() As typAdapters


  Dim returnAdp As typAdapters

   

  Dim Error As Long

  Dim AdapterInfoSize As Long

  Dim i As Long

  Dim PhysicalAddress  As String

  Dim AdapterInfo As typIpAdapterInfo

  Dim Adapt As typIpAdapterInfo

  Dim AddrStr As typIPStrs

  Dim Buffer As typIPStrs

  Dim pAddrStr As Long

  Dim pAdapt As Long

  Dim Buffer2 As typIpAdapterInfo

  Dim AdapterInfoBuffer() As Byte


   

    AdapterInfoSize = 0

    Error = GetAdaptersInfo(ByVal 0&, AdapterInfoSize)

    If Error <> 0 Then

        If Error <> ERROR_BUFFER_OVERFLOW Then

            Debug.Print "GetAdaptersInfo sizing failed with error " & Error

            Exit Function '>---> Bottom

        End If

    End If

    ReDim AdapterInfoBuffer(AdapterInfoSize - 1)



    Error = GetAdaptersInfo(AdapterInfoBuffer(0), AdapterInfoSize)

    If Error <> 0 Then

        Debug.Print "GetAdaptersInfo failed with error " & Error

        Exit Function

    End If

    CopyMemory AdapterInfo, AdapterInfoBuffer(0), Len(AdapterInfo)

    pAdapt = -1

    returnAdp.Count = 0

   

    Do While pAdapt <> 0

        returnAdp.Count = returnAdp.Count + 1

        ReDim Preserve returnAdp.Item(returnAdp.Count)

       

        With returnAdp.Item(returnAdp.Count - 1)

       

            pAdapt = AdapterInfo.tNext

            CopyMemory Buffer2, AdapterInfo, Len(Buffer2)

            Select Case Buffer2.tType

              Case MIB_IF_TYPE_ETHERNET

                .AdapterType = "Ethernet adapter"

              Case MIB_IF_TYPE_TOKENRING

                .AdapterType = "Token Ring adapter"

              Case MIB_IF_TYPE_FDDI

                .AdapterType = "FDDI adapter"

              Case MIB_IF_TYPE_PPP

                .AdapterType = "PPP adapter"

              Case MIB_IF_TYPE_LOOPBACK

                .AdapterType = "Loopback adapter"

              Case MIB_IF_TYPE_SLIP

                .AdapterType = "Slip adapter"

              Case Else

                .AdapterType = "Other adapter"

            End Select

       

            .AdapterName = Buffer2.AdapterName

            .Description = Buffer2.Description

           

            For i = 0 To Buffer2.AddressLength - 1

                PhysicalAddress = PhysicalAddress & Hex$(Buffer2.Address(i))

                If i < Buffer2.AddressLength - 1 Then

                    PhysicalAddress = PhysicalAddress & "-"

                End If


            Next i

            .MacAdress = PhysicalAddress


            .IpAddressCount = 0

            pAddrStr = -1

            Do While pAddrStr <> 0

                .IpAddressCount = .IpAddressCount + 1

                pAddrStr = Buffer2.IpAddressList.tNext


                ReDim Preserve .IpAddress(.IpAddressCount - 1)

           

                CopyMemory Buffer, Buffer2.IpAddressList, LenB(Buffer)

                .IpAddress(.IpAddressCount - 1) = Left$(Buffer.IpAddress, InStr(Buffer.IpAddress, Chr$(0)) - 1)


                pAddrStr = Buffer.tNext

                If pAddrStr <> 0 Then

                    CopyMemory Buffer2.IpAddressList, ByVal pAddrStr, Len(Buffer2.IpAddressList)

                End If

            Loop

        End With

   

        pAdapt = Buffer2.tNext

        If pAdapt <> 0 Then

            CopyMemory AdapterInfo, ByVal pAdapt, Len(AdapterInfo)

        End If

   

    Loop

    GetIPAdapters = returnAdp


End Function


--------- 모듈부분 끝----



--------- 다음은 UserControl에 추가하는 함수입니다. ------


Public Function MacAddr() As String

    Dim a As typAdapters

    Dim tmpVal As String

    Dim i As Integer


    a = GetIPAdapters

    For i = 0 To a.Count

        tmpVal = tmpVal & a.Item(i).MacAdress

    Next

    MacAddr = tmpVal

End Function



위에 있는 mac address를 가져오는 방식은 제가 구상한 것이 아니라 어느 곳인지는 잘 모르지만, 다른 사이트에서 퍼온 것입니다. 어디에서 가져온 것인지 생각이 나지 않네요..


그리고 다음은 Inet 방식으로 ActiveX에서 웹서버의 특정파일에 POST 방식으로 정보를 보내는 것입니다.


Public Sub quitSession()

           

    URL = "http://www...../chkInUser.asp"

    strPostData = "UserCode=" & m_UserCode & "&mode=OUTWEB"

    strPostData = StrConv(strPostData, vbFromUnicode)

    strHeader = "Content-Type: application/x-www-form-urlencoded" & vbCrLf

   

    If Len(m_UserCode) > 0 Then

        Inet1.Execute URL, "POST", strPostData, strHeader

   

        While Inet1.StillExecuting

            DoEvents

            Sleep 1

        Wend

    End If


End Sub


Public Sub keepSession()


    URL = "http://www...../chkInUser.asp"

    strPostData = "UserCode=" & m_UserCode & "&mode=INWEB"

    strPostData = StrConv(strPostData, vbFromUnicode)

    strHeader = "Content-Type: application/x-www-form-urlencoded" & vbCrLf

   

    If Len(m_UserCode) > 0 Then

        Inet1.Execute URL, "POST", strPostData, strHeader

   

        While Inet1.StillExecuting

            DoEvents

            Sleep 1

        Wend

    End If


End Sub



자.. 여기에서 m_UserCode 라는 변수는 유저의 ID 값인데요...

이것은  ASP에서 ActiveX Object를 구성할때 <PARAM name="UserCode" value="2">

로 추가하는 것입니다.


이를 위해서는


Const m_def_UserCode = "0"


'속성 변수:

Dim m_UserCode As String



Private Sub UserControl_InitProperties()


    m_UserCode = m_def_UserCode

End Sub


'저장소에서 속성값을 로드합니다.

Private Sub UserControl_ReadProperties(PropBag As PropertyBag)


    m_UserCode = PropBag.ReadProperty("UserCode", m_def_UserCode)

End Sub


'속성값을 저장소에 기록합니다.

Private Sub UserControl_WriteProperties(PropBag As PropertyBag)


    Call PropBag.WriteProperty("UserCode", m_UserCode, m_def_UserCode)

End Sub



형태로 PARAM 의 UserCode 값을 m_UserCode 로 받습니다.


일단 이렇게 되면

기본적인 함수들의 구성은 끝났고요...



Private Sub UserControl_Show()


    Call keepSession


End Sub


Private Sub UserControl_Terminate()

   

    Call quitSession


End Sub


이렇게 UserControl이 시작될때하고 끝날때 keep 하고 Quit 정보가 웹서버로 전송되게 합니다.

그리고 웹서버의 chkInUser.asp에서는


mode가 INWEB일때는 INUSER 라는 테이블에 UserCode를 로그인 상태로 해놓고

mode가 OUTWEB일때는 INUSER 라는 테이블에 UserCode를 로그아웃 상태로 해놓습니다.


이렇게해놓으면 한가지 단점이 있습니다.

그것은 웹브라우저 종료가 아니라 웹페이지가 이동할때도 Usercontrol_Terminate 이벤트가 작동된다는 것입니다.

그래서 페이지가 로딩될때 UserControl_Show 가 작동되고 페이지를 클릭해서 지금페이지에서 다른페이지로 이동할때 Usercontrol_Terminate 가 되기 때문에 DB에 수시로 업데이트가 된다는 것입니다.


그런데 그런 단점도 iframe이나 기타의 방식으로 통제할 수 있을 꺼라고 봅니다.

2007/11/22 14:59 2007/11/22 14:59
세션은 어떻게 할까...창을 닫아버리면 어쩔까...컴터를 끄면 어쩔까...고민하다가...

QnA에서 힌트를 얻어서...만들었습니다...


필요하신 분은 참고하세요~


우선 두개의 테이블을 만들었습니다...


checklog Table

    - ip(접속 ip)

    - id(사용자 id)

    - loginTime(로그인 시간)


duplicatelog Table (중복접속이 일어났을 경우 로그기록을 남기기 위해서 존재)

    - id(사용자 id)

    - date(날짜)

    - ip(접속 ip)


자주 쓰는 테이블은 checklog Table 하나면 됩니다. 중복체크를 로그기록으로 남기지 않으시면, duplicatelog 테이블은 필요 없습니다.


그래서, 로그인 할때 마다


'로그인 중복 방지#################################################################

        ' 현재날짜 구하기

        strYear = Year(now)

        strMonth = cint(Month(now))

        strDay   = cint(Day(now))

        if cint(strMonth) < 10 then

            strMonth = "0" & strMonth

        end if  

        if cint(strDay) < 10 then

            strDay = "0" & strDay

        end if

        cur_date = strYear & "/" & strMonth & "/" & strDay

        ' 현재날짜 구하기 끝


        ip = Request.Servervariables("REMOTE_ADDR")

        Set dblog=Server.CreateObject("ADODB.Connection")

        dblog.open("logEvent")

        sql = "select * from checklog where id='" & id & "'"

        set rsLog = dblog.execute(sql)

'

        if rsLog.EOF or rsLog.BOF then '중복 로그인이 아님

            sql = "insert into checklog (id, ip, loginTime) values ('"&id&"', '"&ip&"', '"&cur_date&"')"

            dblog.execute sql

        else    '중복 로그인

            sql = "update checklog set id='"&id&"', ip='"&ip&"', loginTime='"&cur_date&"'"

            dblog.execute sql

        end if

'

'       사용자 id로 된 데이터가 없으면 insert를 id로 된 데이터가 있으면 update를 시킵니다.


        dblog.close

        set dblog = nothing

'##############################################################################


그리고, 현재 id와 ip가 맞는지 검사 해주면 되겠죠.

중복 방지가 필요한 페이지에서


'로그인 중복 방지#################################################################  

    ip = Request.Servervariables("REMOTE_ADDR")

    Set dblog=Server.CreateObject("ADODB.Connection")

    dblog.open("logEvent")

    sql = "select * from checklog where id='" & session("mem_id") & "'"

    set rsLog = dblog.execute(sql)    

    if rsLog.EOF or rsLog.BOF then '로그온 안되거나 update 안됨

    else

        if rsLog("ip") <> ip then

            sql = "insert into duplicatelog (id, ip, date) values ('" & session("mem_id") & "', '" & ip & "', '" & rsLog("loginTime") & "')"

            dblog.execute sql

            %>

            <script>

                alert("동일 아이디의 사용자가 접속하여 세션이 종료됩니다.");

                location.class='MIME' href="include/login_ok.asp?sw=logout&returnUrl=<%=Request.ServerVariables("URL")&"?"&Request.ServerVariables("QUERY_STRING")%>";

                // 강제로 로그아웃

            </script>

            <%          

        end if

    end if

    dblog.close

    set dblog = nothing

'로그인 중복 방지#################################################################


저장된 ip와 클라이언트의 ip가 다르면 duplicatelog Table에 기록을 하고, 경고창을 내보내면서...강제로 로그아웃 시킵니다.


그러면 새로 접속된 세션은 살아있으면서 기존에 있던 세션이 끊어지게 되겠죠...기존에 세션이 있다면요...


그리고, 별 필요는 없지만...깔끔하게 정리하기 위해


로그아웃 버튼이 눌렸을때


'로그인 중복 방지#################################################################

Set dblog=Server.CreateObject("ADODB.Connection")

dblog.open("logEvent")

sql = "delete from checklog where id='" & session("mem_id") & "'"

dblog.execute sql

'#################################################################################


만들어진 레코드를 지워놓습니다.


물론, 안 지워도 상관은 없구요~


그럼, 도움이 되셨길...^-^;;;

2007/11/22 14:59 2007/11/22 14:59