DB를 이용한 프로그램을 개발할 경우 요즘은 2-Tier 보다는 보안 문제나 기타 여러가지 이유로 Multi-Tier로 많이 개발하게 됩니다. Multi-Tier로 개발하기 위해서는 DataSnap을 활용하는 방법도 있고, 다양한 델파이 컴퍼넌트나 고가의 Middleware를 사용하는 방법도 있습니다. 그런것도 좋지만 델파이 기본 컴퍼넌트를 활용해서 간단하게 DB Middleware를 한번 구현해 봤습니다.
▣
개발 환경
. Delphi 2007 Enterprise / Indy10 / TSimpleDataSet
▣
통신 규약
☞ 요청
. 구조: [Length] + [Command] + [Data]
구분 | 형태 | 길이 | 설명 |
Length | Integer | 4 Bytes | [Command]와 [Data]의 길이합 |
Command | Char | 1 Byte | E: 쿼리실행(Insert, Delete, Update...) O: Open(Select) |
Data | String | variable | SQL 구문 |
☞ 응답
. 구조: [Length] + [Command] + [Result]
구분 | 형태 | 길이 | 설명 |
Length | Integer | 4 Bytes | [Command]와 [Result]의 길이합 |
Command | Char | 1 Byte |
C: 접속응답
E: 쿼리실행(Insert, Delete, Update...)
O: Open(Select)
X: Error |
Result | TIdBytes | variable |
쿼리실행결과: 적용된 레코드 수
Open(Select)결과: 반환 Data
Error: Error Message |
▣
화면
. 서버 디자인 화면

. 서버 트레이메뉴

. 서버 로그 화면

. 클라이언트 디자인 화면

. 클라이언트 실행 화면 - Open Query

. 클라이언트 실행 화면 - Execute Query

▣
서버 함수 설명
-
procedure UP_AddLog(ALog:
String);
오류나 요청/응답을 모니터링하기위한 로그 처리 함수로 간단하게 TMemo로 처리했지만,
실제 업무용으로 개발할 때는 File에 기록하는게 좋겠죠.
간단한 예제라서 Lock 처리도 안 했는데, 실제 사용할 프로그램에는 반드시 Lock 처리를 해주세요!
-
procedure UP_SendData(
var ACnxt: TIdContext; ACmd: Char; ACont: TIdBytes);
요청에 의해 처리된 결과를 클라이언트로 전송하기위한 함수 입니다.
데모라서 간단하게 만들었기때문에 암호화처리나 압축처리는 없는데 필요하다면 이곳에 추가하면 좋겠죠.
-
procedure UP_ExecQuery(
var ACnxt: TIdContext; ACmd: Char;
var ACont: TIdBytes);
클라이언트에서 요청한 쿼리실행(Insert, Delete, Update...)구문을 처리하기 위한 함수입니다.
처리후 오류가 없다면 적용된 레코드 수를 요청한 클라이언트로 반환합니다.
-
procedure UP_OpenQuery(
var ACnxt: TIdContext; ACmd: Char;
var ACont: TIdBytes);
Open요청된 SQL 구문을 받아서 조회된 결과를 클라이언트로 전송합니다.
복잡하게 구현하지않고 TClientDataSet의 SaveToStream을 활용해서 처리했고,
클라이언트 역시 TClientDataSet을 활용해서 반환된 결과를 조작없이 그대로 활용하였습니다.
-
procedure UP_KillClient(AAll: Boolean = True);
비정상적으로 클라이언트가 죽을 경우 Indy Socket 특성상 서버에는 남아있게 됩니다.
그렇게 남겨진 컨넥션을 일정시간마다 돌면서 체크해서 죽이는 프로시져입니다.
그런 처리를 위해서 각 클라이언트마다 TSDDB라는 TObject에 요청시 최종요청시간을 갱신하고,
서버 구동시 Active 시킨 타이머에 의해 일정 시간마다 현재시간과 최종요청시간을 비교해서
일정시간이 경과한 클라이언트를 죽여버립니다.
▣
기타 팁
. 2-Tier 개발시 처럼 쿼리컴퍼넌트에서 삭제/저장/추가시 자동으로 서버에 적용하기 위해서는
클라이언트 측의 TClientDataSet의 AfterDelete/AfterPost Envet에 서버로 쿼리실행 커맨드를 요청하는 처리를 추가하면 됩니다.
기본적인 처리를 구현한 Form을 상속받아서 코딩하면 좀더 쉽게 개발이 가능하겠죠?
. 일정 시간이 지나도록 요청이 없을 경우 자동으로 죽여버리는 처리때문에 클라이언트 접속이 강제 종료될 수 있는데,
아래와 같은 방법으로 접속을 유지시켜주면 강제 종료를 막을 수 있습니다.
방법 1. 일정 시간마다 의미없는 쿼리를 요청.
방법 2. 더미 처리를 위한 커맨드를 추가하고 일정 시간마다 더미 처리용 커맨드를 요청.
. 빈번한 요청이 없고 DB Server 성능이 떨어지는 환경이라면 요청후 DB 접속을 끊는 방법도 괜찮겠죠.
단, 요청이 빈번한 경우 DB에 접속하는 시간때문에 역효과가 날 수도 있습니다.