WBAPI

WebtoB는 기존 CGI 방식의 애플리케이션 프로그램들의 문제점을 해결하기 위해 새로운 WebtoB만의 API를 제공한다. 본 장에서는 WebtoB에서 제공하는 API에 대해서 설명한다.

1. 개요

기존의 CGI 방식은 사용자의 요구가 발생하는 경우마다 새로운 프로세스가 시작되어 사용자의 요구를 처리한다. 사용자가 새로운 요구를 하면 그 순간에 시스템의 운영체제가 그 프로그램에 해당하는 프로세스를 Fork하는 작업을 수행하게 한다. 새로운 프로세스를 Fork하는 작업은 시스템 자체에 부하를 걸게 되고, 이런 일이 많아지게 되면 시스템에 많은 부담을 준다. 이런 문제점 때문에 기존 CGI 사용자들은 점차 새로운 애플리케이션으로 관심을 돌리게 되었고, Servlet, PHP, ASP, JSP 등이 등장하였다.

이런 프로그램은 모두 C로 만들어진 프로그램이 아니라 Java나 스크립트 등을 이용한 새로운 형태의 프로그램들이다. 따라서 새로운 개발에는 용이할지 몰라도 기존 C Style로 CGI 프로그램들을 개발하여 운영해 온 사람들에게는 기존 프로그램들을 모두 폐기하고 새로 만들어야 하는 부담을 안겨주고 있다.

CGI 개발자들은 자신들이 운영하던 CGI를 버리고 완전히 새로운 프로그램을 도입할 것인지, 아니면 기존 프로그램을 운영하되 서버를 늘려서 CGI의 부담을 줄일 것인지 고민한다. WebtoB에서는 기존 CGI 개발자들의 고민을 해결해주기 위해 새로운 형태의 API를 개발하였다.

제공되는 API는 C Style의 프로그램을 위한 API로서 CGI 프로그램의 부담을 덜고 기존 CGI 프로그램의 수정은 최소화할 수 있게 한다. 이를 통해 기존 CGI 프로그램으로 서비스를 해 오던 많은 사용자들은 부담도 덜고, 성능도 향상시킨다.

2. 개념

CGI 방식은 위에서 언급한 대로 사용자가 요구할 때마다 매 순간 새로운 프로그램이 Fork되고 처리가 끝나는 순간 Exit되는 일을 반복한다. 이는 다른 처리를 해야 할 시간에 새로운 프로세스를 메모리에 로드하고 스케줄링을 해야 하는 등의 많은 작업을 해야 하기 때문에 시스템의 관점에서는 굉장히 큰 부담이다.

다음 그림은 Apache 웹 서버에서의 CGI를 사용하는 모습을 나타낸다.

figure 8 3
Apache에서의 CGI 동작 방식

위 그림을 보면 웹 서버가 Request를 요청할 때마다 CGI가 Fork되는 로드가 생길 수 밖에 없다.

WebtoB에서 제공하는 WBAPI는 우선 CGI의 이런 점을 개선하였다. 즉, 사용자가 요구를 보내는 매 순간에 프로세스를 Fork하는 것이 아니라, 웹 서버가 Boot Up되는 시점에 이러한 프로그램들을 미리 Fork하여 메모리에 올려 놓는 것이다. 또한, 사용자의 요구에 대한 처리가 끝난 시점에서도 Exit 되는 것이 아니라, 계속 메모리에 상주하여 다음 요구를 기다리는 것이다. 결국 매 순간 프로세스가 Fork되고 Exit되는 부담이 줄어들게 되는 것이다.

또한 단순히 이러한 부담을 줄이는 외에도 이 WBAPI로 설계된 프로그램의 관리를 WebtoB가 담당하게 된다. 따라서 만약 사용자의 부주의나 설계 오류로 프로그램이 다운되거나 문제가 생겼을 때 즉각 새로운 프로그램을 다시 실행할 수 있게 하는 등의 기능이 추가되었다. WebtoB는 프로그램들의 수를 조정해서 특정 프로그램에 대한 요구가 많다고 판단되면 이를 미리 많이 실행시켜서 부하를 줄인다.

WebtoB의 WBAPI의 호출을 그림으로 나타내면 다음과 같다.

figure 8 4
WebtoB에서의 WBAPI

WBAPI는 main()으로 시작하는 일반 함수와는 다르다. 이는 WBAPI로 작성한 프로그램들이 독립된 프로세스로 발생하기는 하지만, 실제 WebtoB의 내부와 연결된 프로세스로 동작하기 때문이다. 따라서 함수의 시작이 일반적인 main()이 아닌 Service Name이라는 것으로 시작하게 된다. 따라서 함수의 시작되는 이름이 반드시 Service Name이 되어야 하고, 이는 WebtoB의 환경 파일에 등록이 되어 있어야 한다. 이에 대한 자세한 내용은 이후에 설명될 환경설정을 참고한다.

3. 환경설정

WebtoB에서 WBAPI를 사용하기 위해서는 프로그램의 작업과 함께 WebtoB의 환경설정이 필요하다. 즉, WebtoB에 WBAPI를 이용하여 프로그램을 개발하였고, 이는 이렇게 이용하겠다는 식의 등록을 한다.

다음은 WebtoB의 환경 파일에 대한 예이다. 아래 설정 파일에서 진한색으로 처리된 부분이 실제 WBAPI를 사용하기 위한 기본 설정이다.

*DOMAIN
webtob1

*NODE
webmain
    WebtoBDir = "/usr/local/webtob",
    SHMKEY = 99000,
    Docroot = "/usr/local/webtob/docs",
    AppDir = "/usr/local/webtob/ap",
    Hostname = "webmain.tmax.co.kr",
    Port = "8080",
    JsvPort = 9099

*SVRGROUP
cgig    NodeName = webmain, SvrType = CGI
jsvg    NodeName = webmain, SvrType = JSV
ssig    NodeName = webmain, SvrType = SSI
wbapg  NodeName = webmain, SvrType = WEBSTD

*SERVER
cgi     SvgName = cgig, MinProc = 10, MaxProc = 10
ssi     SvgName = ssig, MinProc = 2, MaxProc =2
jsv1    SvgName = jsvg, MinProc = 10, MAXProc = 10
webaps SvgName = wbapg, MinProc = 5, MAXProc = 5

*SERVICE
write_board  SvrName = webaps

*URI
uri1  Uri ="/svct/", SvrType = WEBSTD, SvrName = webaps
  • SVRGROUP 절

    webmain라는 이름의 Host 머신에 wbapg라는 서버 그룹을 설정하고, 이것이 WBAPI를 사용하기 위한 WEBSTD라는 서버 유형으로 설정한다.

    wbapg        NodeName = webmain, SvrType = WEBSTD
  • SERVER 절

    SVRGROUP 절에 설정된 wbapg에 있는 것이 webaps라는 서버로 정의되어 있음을 나타낸다.

    webaps       SvgName = wbapg, MinProc = 5, MaxProc = 5

SVRGROUP 절, SERVER 절이 항상 설정되어야 할 기본이다. 이는 대부분의 환경에서 Host 머신의 이름만 다를 뿐 별 차이가 없다. 실제 서비스를 응용하기 위해서는 각 서비스에 대한 설정이 추가로 필요하게 된다.

  • SERVICE 절

    WBAPI로 개발된 프로그램의 등록을 한다. 실제 프로그램의 함수명과도 같은데 WBAPI로 개발된 프로그램이 일반 C Style과 달리 write_board()로 시작한다. 즉, 이 함수 시작 이름이 서비스의 이름이 되는 것이다. 따라서 등록할 때 이 이름으로 등록을 한다. SERVICE 절은 SERVER 절 다음에 추가한다.

    *SERVICE
    write_board    SvrName = webaps
  • URI 절

    WBAPI로 만든 서비스를 사용할 때 URI 절을 설정한다. 요청에 특정 URI, 즉 "/svct/" 라는 URI로 시작하는 경우 WBAPI 서비스로서 실행시키겠다는 의미이다.

    *URI
    uri1        Uri =”/svct/”,
                SvrType = WEBSTD,
                SvrName = webaps

4. 서비스 테이블 생성

보통 WebtoB를 기동하기 위해서는 wscfl을 통해서 컴파일만 하면 되지만 WBAPI를 사용하기 위해서는 wscfl로 컴파일한 후 서비스 테이블을 생성해야 한다. bin/ 디렉터리 안에 있는 wsgst라는 명령어를 사용해서 생성한다. wsgst를 수행하면 WebtoB는 WBAPI를 쓰기 위한 '_svctab.c’라는 확장자를 가진 서비스 테이블을 지정된 경로에 생성한다.

wsgst

다음은 wsgst 명령을 사용해서 서비스 테이블을 사용하는 방법과 옵션에 대한 설명이다.

  • 사용법

    $ wsgst [-f 이진 WebtoB 환경파일 이름]
    옵션 설명

    [-f 이진 WebtoB 환경파일이름 ]

    서비스 테이블을 생성할 때 참조하는 환경 파일이 wsconfig 아닌 경우 이 이름을 지정한다.

  • 예제

    다음은 wsgst을 사용하는 예제이다.

    $ wsgst   (Default로 wsconfig를 참조한다)
    $ wsgst -f wsconfig2   (wscfl -o를 사용한 경우)

이로써 WBAPI를 사용하기 위한 모든 준비가 완료되었다. 이제 WBAPI로 개발된 프로그램을 컴파일하여 실행 파일을 생성하고 이를 위와 같은 형식으로 등록한다.

5. 프로그램의 컴파일

WBAPI로 개발된 프로그램은 C에서 기본적으로 제공되는 라이브러리 외에도 WebtoB에서 제공하는 특수한 라이브러리 및 서비스 테이블 파일을 이용하기 때문에 이를 컴파일할 때 연결해 주어야 한다.

아래는 UNIX/Linux에서 사용하는 컴파일을 위한 Makefile 파일의 예제이다.

#Makefile.common
TARGET= webaps
APOBJS= ap.o

#hp 32bit
CFLAGS = -Ae +DA1.1 +DD32 -O -I$(WEBTOBDIR)
#hp 64bit
#CFLAGS = -Ae +DA2.0W +DD64 +DS2.0 -O -I$(WEBTOBDIR)
#sun 32bit
#CFLAGS = -O -I$(WEBTOBDIR)
#sun 64bit
#CFLAGS = -xarch=v9 -O -I$(WEBTOBDIR)
#Linux
#CFLAGS = -O -I$(WEBTOBDIR)
#ibm 32bit
#CFLAGS = -q32 -O -I$(WEBTOBDIR) -brtl
#ibm 64bit
#CFLAGS = -q64 -O -I$(WEBTOBDIR) -brtl

WEBTOB_INCDIR = $(WEBTOBDIR)/usrinc
WEBTOB_BINDIR = $(WEBTOBDIR)/bin
WEBTOB_LIBDIR = $(WEBTOBDIR)/lib
OBJS    = $(APOBJS) $(SVCTOBJ)
SVCTOBJ = $(TARGET)_svctab.o

.SUFFIXES : .v
.c.o:
        $(CC) $(CFLAGS) -c $<

wbaps: $(APOBJS) svct
        $(CC) $(CFLAGS) -L$(WEBTOB_LIBDIR) -o $(TARGET) $(OBJS) $(LIBS) $(USERLIBS)

svct:
        cp $(WEBTOBDIR)/svct/$(TARGET)_svctab.c .
        $(CC) $(CFLAGS) -I$(WEBTOB_INCDIR) –c $(TARGET)_svctab.c

다음은 Windows의 경우이다.

#Makefile for Windows
TARGET = webaps.exe

LIBS    = /link $(WEBTOBDIR)\lib\aps.lib ws2_32.lib
CFLAGS  = /D _DEBUG /I $(WEBTOBDIR) /Gd /MD /nologo

APOBJ   = $(TARGET:.exe=.obj)
SVCTSRC = $(TARGET:.exe=_svctab.c)
SVCTOBJ = $(TARGET:.exe=_svctab.obj)
OBJS    = $(APOBJ) $(SVCTOBJ)

$(TARGET): svct $(OBJS)
        cl $(CFLAGS) -o $@ $(OBJS) $(LIBS)
        copy $@ $(WEBTOBDIR)\ap

svct:
        copy $(WEBTOBDIR)\svct\$(SVCTSRC)

clean:
        -del $(OBJS) $(TARGET)

6. WBAPI의 시작 및 응용

작업이 완료되면 WebtoB가 기동될 때 WBAPI로 개발된 프로그램을 같이 실행시켜 프로세스 형태로 메모리에 로드된다.

CGI를 변환하는 것은 WBAPI의 기능 중의 일부이다. 기존 CGI의 변환 외에도 C Style에 능숙한 사람들은 새로운 애플리케이션을 개발할 때 이 WBAPI를 이용하면 개발의 편의성 및 성능 향상에도 많은 도움이 될 것이다. WebtoB는 지속적으로 WBAPI를 제공하고 또 향상할 것이므로 차후의 확장성이나 지원등에서 무리가 없을 것이다.

그리고 이 WBAPI를 통해서 기존 TP-Monitor에서 제공한 서비스 기능을 이용하는 것도 가능하다.

7. WBAPI의 종류

WBAPI는 각각 INIT/DONE, ALLOC, GET, PUT/SET, SEND, COOKIE, SESSION, ETC 계열로 구성되어 있다. WBAPI는 기능별로 나누어진 것으로 각각의 API에 대한 간단한 설명을 한다.

7.1. INIT/DONE API

INIT/DONE 계열의 함수는 개발자가 서비스를 시작하기 전의 초기화 과정이나 서비스 프로세스가 종료될 때 수행되어야 할 루틴을 수행한다.

다음은 INIT/DONE 계열 함수의 목록이다.

함수 이름 기능

wbSvrInit()

서버를 초기화한다.

wbSvrDone()

WebtoB의 반환을 알리는 함수이다.

7.2. ALLOC API

ALLOC 계열의 함수는 사용자가 메모리를 할당하고 해제한다.

다음은 ALLOC 계열 함수의 목록이다.

함수 이름 기능

wbMalloc()

사용자가 설정한 SIZE만큼의 메모리를 할당한다.

wbFree()

wbMalloc()에 의해 할당된 메모리를 제거(free)한다.

7.3. GET API

GET 계열의 함수는 사용자가 요청한 것에 대하여 사용자의 정보를 읽어들이는 것으로 사용자의 Request의 데이터, 메소드 정보 값 등을 알아낸다.

다음은 GET 계열 함수의 목록이다.

함수 이름 기 능

wbGetAuthType()

사용자의 인증방식을 얻어낸다.

wbGetContentLength()

클라이언트가 보낸 Content의 크기를 얻어낸다.

wbGetDocumentRoot()

WebtoB의 Home 디렉터리의 값을 얻어낸다.

wbGetHdr()

Request의 헤더에서 특정 Key에 해당하는 값을 얻는다.

wbGetDateHdr()

데이터를 표현하는 헤더를 얻는다.

wbGetIntHdr()

지정된 헤더 값을 정수 형태로 얻는다.

wbGetNthHdr()

헤더에서 n번째에 해당하는 헤더 값을 얻는다.

wbGetHdrCount()

사용자가 보낸 Request의 헤더의 총 개수를 얻는다.

wbGetData()

Request의 데이터 필드에서 Key에 해당하는 값을 얻는다.

wbGetNthKey()

Request에서 n번째의 Key에 대한 데이터를 얻는다.

wbGetNthData()

Request의 데이터에서 n번째 데이터를 얻는다.

wbGetDataCount()

Request에서 입력으로 들어온 데이터의 숫자를 얻는다.

wbGetValue()

Request에서 특정 Key 값의 n번째 데이터를 얻는다.

wbKeyOccur()

Request로 들어온 데이터에서 Key 값의 수를 얻는다.

wbGetMethod()

Request로 들어온 HTTP 메소드를 정수형으로 읽어 들인다.

wbGetParsedURI()

클라이언트로부터 Request가 들어온 URI 정보를 얻어낸다.

wbGetPathInfo()

Request와 관계된 상대 경로 정보를 얻어낸다.

wbGetPathTranslated()

Request와 관계된 절대 경로 정보를 얻어낸다.

wbGetQueryString()

Request URL로부터 질의어 문자열을 얻어낸다.

wbGetProtocol()

Request와 관계된 프로토콜 정보를 얻어낸다.

wbGetRemoteUser()

Request하는 사용자의 이름을 얻어낸다.

wbGetRequestURI()

Request URI를 얻어낸다.

wbGetRemoteAddr()

Request한 Remote Host의 IP를 얻어낸다.

wbGetRemoteHost()

Request하는 Remote Host의 이름을 얻어낸다.

wbGetRemoteIdent()

서버로부터 검색된 사용자의 이름을 얻어내는 데 사용된다.

wbGetReqLine()

Request에 들어온 line의 첫 번째 line pointer를 얻는다.

wbGetFileName()

파일의 이름을 알아낸다.

wbGetFileLen()

파일의 크기를 알아낸다.

wbGetScheme()

Request된 서비스의 프로토콜 정보를 얻어낸다.

wbGetScriptFileName()

Request한 WBAPI 서비스가 실행되는 절대 경로를 얻어낸다.

wbGetScriptName()

Request한 서비스가 실행되는 경로를 얻어낸다.

wbGetServerName()

서버의 hostname을 얻어낸다.

wbGetServerPort()

서버의 포트 번호를 얻어낸다.

wbGetServerSoftware()

서버의 소프트웨어 정보를 얻어낸다.

wbGetTranslatedURI()

Request된 서비스의 URI를 해석하여 실제 경로를 얻어낸다.

wbGetRequestURL()

Request URL 값을 얻어낸다.

7.4. PUT/SET API

PUT/SET 계열의 함수는 사용자의 Request에 대한 응답으로 WBAPI에서 처리한 값을 출력하기 위한 용도로 쓰이는 것으로 CGI에 익숙한 사람이라면 출력값을 나타내기 위하여 C 언어의 printf 함수나 Perl의 print 스크립트를 이용하는 것과 같다고 보면 된다.

WBAPI에서는 print 스크립트에 대한 처리를 한 후 그 결과를 WBSVCINFO라는 구조체에 저장하여 그 구조체를 브라우저에 넘기는데 이 WBSVCINFO 구조체에 응답으로 보낼 데이터를 저장하는 역할을 하는 함수들이다.

PUT 계열 함수를 이용할 때는 몇 가지 주의 사항이 있는데 PUT 관련 함수들은 순서를 지켜주어야 WBAPI가 문제없이 수행된다.

  • 다른 PUT 계열 함수들보다 먼저 수행되어야 하는 함수가 있다.

    wbSetStatus(WBSVCINFO *rqst, int status, char *status_msg) 함수는 Response 헤더를 먼저 작성하는 함수로 먼저 수행되어야 한다.

  • PUT 관련 함수 중에서 헤더를 작성하는 함수들이 데이터 필드를 작성하는 함수들보다 먼저 선언되어야 한다.

다음은 PUT/SET 계열 함수의 목록이다.

함수 이름 기 능

wbPutHdr()

Response 헤더를 설정한다.

wbPutIntHdr()

Response 헤더를 추가한다.

wbSetStatus()

Request의 status 값을 설정한다.

wbPutStr()

string 값을 출력한다.

wbPut()

특정 사이즈만큼의 데이터를 출력한다.

wbPrint()

사용자가 지정한 내용을 출력한다.

wbPutFile()

File download를 위한 함수, 특정 파일을 읽어들여 모두 브라우저로 보내준다.

wbPutPartialFile()

File download를 위한 함수로 특정 파일의 ‘일부분’을 읽어서 브라우저로 보내준다. File의 offset부터 사이즈만큼 읽어서 들여 보내준다. 사이즈가 0이면 파일 끝까지 읽어 보내준다.

7.5. SEND API

SEND 계열은 사용자의 Request에 대한 응답으로 PUT 계열 함수를 사용하여 WBSVCINFO 구조체에 서비스 처리 결과를 저장한 것을 브라우저에 리턴하는 함수이다.

다음은 SEND 계열 함수의 목록이다.

함수 이름 기능

wbFlush()

현재 버퍼에 있는 모든 내용을 기록하게 한다.

wbSendError()

상태코드의 에러 여부를 확인한다.

wbSendRedirect()

지정된 주소로 응답을 되돌려준다.

wbReturn()

WebtoB의 반환을 알려준다.

COOKIE 계열 함수는 HTTP 스타일의 Cookie를 생성하고, 읽고 처리하기 위한 작업을 수행한다.

다음은 COOKIE 계열 함수의 목록이다.

함수 이름 기 능

wbCreateCookie ()

새로운 Cookie를 생성한다.

wbGetCookie()

브라우저에 의해 보내진 Cookie 중에서 원하는 Cookie를 리턴한다.

wbPutCookie()

지정된 Cookie에 응답을 덧붙인다.

wbCookieGetDomain ()

지정된 Cookie에서 도메인을 리턴한다.

wbCookieGetName()

지정된 Cookie의 이름을 리턴한다.

wbCookieGetPath()

Cookie의 경로를 리턴한다.

wbCookieGetValue()

Cookie의 값을 리턴한다.

wbCookieGetVersion()

Cookie의 버전을 리턴한다.

wbCookieSetComment()

Cookie의 주석 필드를 설정한다.

wbCookieSetDomain()

Cookie의 도메인을 설정한다.

wbCookieSetMaxAge()

Cookie의 수명시간을 설정한다.

wbCookieSetPath()

Cookie를 위한 경로를 설정한다.

wbCookieSetSecure()

Cookie가 SSL과 같이 보호되는 프로토콜에서 전송되어야 하는지를 설정한다.

wbCookieSetValue()

Cookie에 새로운 값을 설정한다.

wbCookieSetVersion()

Cookie에 새로운 버전을 설정한다.

7.7. SESSION API

SESSION 계열 함수는 세션을 생성하고, 세션의 고유 정보를 얻어 기타 작업들을 수행할 수 있도록 한다.

다음은 SESSION 계열 함수의 목록이다.

함수 이름 기 능

wbGetRequestedSessionId()

사용자에 요청에 의해 명확해진 세션 ID를 얻어낸다.

wbGetSession()

생성된 세션이 없는 경우 세션을 생성하고 그 세션 값을 얻어낸다.

wbIsRequestedSessionIdValid()

요청된 세션이 올바른 세션이고 현재 사용 중이라면 true값을 얻어낸다.

wbSessionGetId()

세션에 할당된 유일한 ID를 얻는다.

wbSessionGetValueNames()

세션에 바인딩된 모든 객체의 이름을 포함하는 배열을 얻어낸다.

wbSessionGetCreationTime()

세션이 생성된 시간을 얻어낸다.

wbSessionGetValue()

세션에 바인딩된 객체의 값과 이름을 얻어낸다.

wbSessionSetValue()

세션에 지정된 객체의 값과 이름을 바인딩한다.

wbSessionIsNew()

세션이 새로운 것인지 아닌지 나타내는 값을 얻어낸다.

wbSessionRemoveValue()

지정된 이름에 바인딩된 객체를 제거한다.

WbSessionInvalidate()

세션을 무효화한다.

wbSessionGetMaxInactiveInterval()

세션에 설정된 세션 유지 시간을 얻어낸다.

wbSessionSetMaxInactiveInterval()

지정된 세션에 세션 유지 시간을 설정한다.

wbSessionGetLastAccessTime()

클라이언트가 마지막으로 요청을 보낸 시간을 얻어낸다.

7.8. ETC API

ETC 계열 함수는 WebtoB에 File Upload 수행하거나 WebtoB 에러 번호를 얻을 수 있다.

다음은 ETC 계열 함수의 목록이다.

함수 이름 기 능

wbGetErrno()

WebtoB의 에러 번호를 얻어낸다.

wbSaveFile()

File Upload를 위한 함수이다.

8. WBAPI를 이용한 CGI의 변환

WBAPI는 차후에 Multi Thread 기능을 제공할 예정이다. 이를 위하여 각각의 함수마다 특정 자료 구조(Data Structure)를 선언하는 것이 필요하다. 처음 WBAPI 프로그램을 작성하게 되면 Service Name을 등록하게 되는데 이때 WBSVCINFO라는 구조를 선언하게 되어 있다. 이를 WBAPI 내부의 각각의 함수의 앞에 반드시 입력해야 한다. 따라서 한 WBAPI 프로그램 내부의 모든 WBAPI 함수는 Service Name이 선언된 구조를 함수의 첫 번째 인자로 가지고 있어야 한다.

본 절에서는 WBAPI를 이용하여 기존의 CGI 프로그램을 변환할 때 어떤 방식으로 이루어지는지 설명한다.

8.1. CGI 프로그램

다음은 CGI 방식을 이용해서 간단한 게시판을 구현하는 프로그램의 예이다.

#include "qDecoder.h"

int strcheck(char *str) {
       if (str == NULL)
              return 0;
       if (strlen(str) == 0)
              return 0;
       return 1;
}

int main(void) {
       char *name, *title, *doc;
       char *email, *homepage;

       /* 입력값들을 얻어냄 */
       name = qValue("writer");
       title = qValue("title");
       doc = qValue("doc");
       email = qValue("email");
       homepage = qValue("homepage");

       /* 입력값들이 올바른지 검사 */
       if (!strcheck(name))
              qError("이름을 입력하세요.");
       if (!strcheck(title))
              qError("글 제목을 입력하세요.");
       if (!strcheck(doc))
              qError("본문을 입력하세요.");
       if (strcheck(email))
              if (!qCheckEmail(email))
                        qError("E-Mail 주소를 정확히 입력하세요.");
       if (strcheck(homepage))
              if (!qCheckURL(homepage))
                        qError("Homepage URL을 정확히 입력하세요.");

       /* 처리결과출력 – 입력확인 */
       qContentType("text/html");
       printf("<HTML>\n\n");
       printf("<HEAD><TITLE>Bestbook 게시판 – 글 올리기 확인</TITLE></HEAD>\n\n");
       printf("<BODY>\n");
       printf("<H2> Bestbook 게시판 - 글 올리기 확인 </H2>\n");
       printf("<HR WIDTH=600 ALIGN=left>\n<BR>");

       if (strcheck(email))
             printf("<A HREF=\"mailto:%s\">%s</A>", email, name);
       else printf("%s", name);

       if (strcheck(homepage))
             printf("<SMALL>(<A HREF=\"%s\">%s</A>)</SMALL>", homepage, homepage);

             printf("올리신 글은 다음과 같습니다.<BR><BR>\n");
             printf("<TABLE WIDTH=600 BORDER=1>\n");
             printf("<TR><TD><B>제목</B> : %s</TD></TR>\n", title);
             printf("<TR><TD>%s</TD></TR>\n", doc);
             printf("</TABLE>\n\n<BR>이 글이 정상적으로 게시판에 올려졌습니다.\n");
             printf("</BODY>\n\n</HTML>");
             qFree();
}

대부분의 CGI 프로그램의 구조는 간단하고 단순하다. QUERY_STRING을 통해서 전달된 사용자의 입력 값을 바탕으로 특정한 작업을 수행한 후 이를 HTML 문서와 같은 형태로 다시 전달한다. HTML 형태의 문서를 만드는 것은 주로 printf 함수를 통하여 이루어진다.

프로그램에 있는 여러 함수들은 거의 C 언어에서 기본적으로 제공하는 것이고, qValue나 strcheck 등의 처리 함수들은 입력변수의 값을 읽어 오거나, 변수 값이 맞는지 분석하는 함수들이다. 이 역시 간단한 라이브러리 형태로 지원된다.

위의 CGI 프로그램을 분석하면 다음과 같다.

  1. CGI 프로그램에서는 writer, title, doc, email, homepage란 변수를 이용한다. 따라서 사용자는 이들 변수의 값을 전달한다. 아래의 프로그램은 사용자가 전달한 값을 CGI 프로그램에서 인식하기 위하여 분리하는 과정이다.

    각각의 변수에 qValue라는 함수를 이용하여 값을 읽어낸다.

    name = qValue("writer");
    title = qValue("title");
    doc = qValue("doc");
    email = qValue("email");
    homepage = qValue("homepage");
  2. 각각의 변수값을 읽어낸 후 아래의 strcheck 함수를 통해서 각각의 변수 값이 모두 입력되었는지 확인한다.

    if (!strcheck(name))
               qError("이름을 입력하세요.");
    
    if (!strcheck(title))
               qError("글 제목을 입력하세요.");
    
    if (!strcheck(doc))
               qError("본문을 입력하세요.");
    
    if (strcheck(email))
       if (!qCheckEmail(email))
           qError("E-Mail 주소를 정확히 입력하세요.");
    
    if (strcheck(homepage))
        if (!qCheckURL(homepage))
             qError("Homepage URL을 정확히 입력하세요.");
  3. 함수들을 모두 정상적으로 수행하였다면 CGI로 전달된 사용자의 변수 값이 모두 이상이 없다는 것이다. 이제 게시판에 값을 올리고 출력 형태를 만들어야 한다.

    아래의 함수는 이 CGI 프로그램이 제공하는 출력 형태가 HTML임을 나타내고 있다.

    qContentType("text/html");
  4. printf 함수를 통하여 결과 값을 만들어내는 작업을 수행한다. 이는 HTML 문서를 실제로 Editing하는 것과 거의 같다.

    다음을 보면 printf 함수를 통해서 HTML Tag를 만들어 낸다.

    printf("<HTML>\n\n");
    printf("<HEAD><TITLE>Bestbook 게시판 – 글올리기 확인</TITLE></HEAD>\n\n");
    printf("<BODY>\n");
    printf("<H2> Bestbook 게시판 – 글 올리기 확인</H2>\n");
    printf("<HR WIDTH=600 ALIGN=left>\n<BR>");
    
    if (strcheck(email))
              printf("<A HREF=\"mailto:%s\">%s</A>", email, name);
    else printf("%s", name);
    
    if (strcheck(homepage))
              printf("<SMALL>(<A HREF=\"%s\">%s</A>)</SMALL>", homepage, homepage);
    
    printf("올리신 글은 다음과 같습니다.<BR><BR>\n");
    printf("<TABLE WIDTH=600 BORDER=1>\n");
    printf("<TR><TD><B>제목</B> : %s</TD></TR>\n", title);
    printf("<TR><TD>%s</TD></TR>\n", doc);
    printf("</TABLE>\n\n<BR>이 글이 정상적으로 게시판에 올려졌습니다.\n");
    printf("</BODY>\n\n</HTML>");

8.2. WBAPI 프로그램

다음은 CGI 프로그램과 똑같은 기능을 하는 WBAPI 프로그램이다. 구조적인 것은 CGI 프로그램과 같다.

  1. 각각의 변수에 대한 값을 읽어내야 한다.

    CGI 프로그램은 qValue라는 함수를 사용하는데, WBAPI에서는 wbGetData라는 함수를 사용한다. 아래의 함수들은 위의 CGI에서 qValue를 통해서 수행된 것을 그대로 수행하는 것이다. 결국 각각의 변수값을 읽어들이게 된다.

    writer = wbGetData(rqst, "writer");
    title = wbGetData(rqst, "title");
    doc = wbGetData(rqst, "doc");
    email = wbGetData(rqst, "email");
    homepage = wbGetData(rqst, "homepage");
  2. 변수를 읽어 들인 값을 확인하는 과정은 strcheck를 이용한다. 처리 방법은 CGI 프로그램과 동일하다.

  3. WBAPI에서는 사용자의 환경변수 뿐만 아니라, 헤더에 전송된 값도 읽어 들일 수 있다. 이것은 아래와 같은 wbGetHdr 함수를 통하여 이루어진다.

    다음은 Content-Length 값을 읽어 들이는 방법이다.

    hd = wbGetHdr(rqst, "Content-Length");
  4. 일련의 작업들이 끝났다면 이제 출력을 위한 문서를 만들어야 한다.

    CGI 프로그램에서는 printf 함수로 처리된 것이었다. WBAPI에서는 wbPrint라는 함수로 처리된다. 결국 기존의 CGI에서 printf 함수를 썼던 부분을 모두 wbPrint로 처리하면 된다. 결과 형태가 약간 달라질 수 있지만 이는 출력 형태인 HTML Tag가 약간 변화한 것일 뿐 게시판을 만든다는 것에는 변화가 없다.

    CGI 프로그램에서 printf를 통하여 만들어진 헤더 정보는 이곳에서는 wbPutHdr를 통해서 생성된다. 결국 HTML 안에 포함되는 것만 wbPrint를 이용하고 헤더 정보는 wbPutHdr를 이용한다.

    다음은 헤더를 생성하는 예제이다.

    wbPutHdr(“ContentType”, “text/html");

    다음은 HTML Tag를 생성하는 예제이다.

    wbPrint(rqst, "<HTML>\n\n");
    wbPrint(rqst, "<HEAD> <TITLE> webtob Write Board </TITLE> </HEAD>\n\n");
    wbPrint(rqst, "<BODY>\n");
    wbPrint(rqst, "<H2> Bestbook</H2>\n");
    wbPrint(rqst, "<H3>Writer is%s </H3> \n",writer);
    wbPrint(rqst, "<H3>Title is%s </H3> \n",title);
    wbPrint(rqst, "<HR>\n");
    wbPrint(rqst, "<H2> %s </H2> \n",doc);
    wbPrint(rqst, "<H3> newvalue :%s%d</H3> \n",hd,rt);
    wbPrint(rqst, "<HR ALIGN=left>\n<BR>");
    wbPrint(rqst, ".<BR><BR>\n");
    wbPrint(rqst, "<TABLE WIDTH=600 BORDER=1>\n");
    wbPrint(rqst, "</TABLE>\n\n<BR>.\n");
    wbPrint(rqst, "</BODY>\n\n</HTML>");
  5. 위의 모든 작업이 끝나면 결과가 끝났다는 것을 마지막에 return 대신에 wbReturn을 수행하는 것으로 WebtoB에 전달한다.

    wbReturn(rqst, WBSUCCESS);

    괄호 안의 WBSUCCESS는 결과가 성공적으로 수행되었다는 것을 나타낸다.