3.HTML파일 보기와 FTP 프로그램

인터넷을 이용한 프로그램이라면 당연하게 웹브라우저 같은 프로그램이나 FTP프로그램을 말할것입니다. 웹브라우저를 만드는 중요 로직은 HTML파일을 분석하고 자바 실행파일을 분석하여 해당하는 내용을 화면에 출력하는 것과 LAN상에서 HTTP프로토클로 접속하여 HTML파일이나 또는 그외의 필요한 파일을 다운 받는 것입니다.HTML파일분석은 본편에서 설명을 하지않습니다. 다만 HTML파일을 다운 받아서 그내용을 화면에 출력하는 방법을 설명합니다. FTP프로그램은 특정 서버에 접속하여 디렉토리를 이용하고 파일을 다운,업로드 시키는 방법을 설명합니다. 본장을 통해서 웹브라우저를 만들 때 기본이 되는 HTTP와 FTP를 완벽 활용할수 있는 방법을 배우게 될것입니다.

대상: 중급,고급

구분: 선택

공부방법: FTP나 HTTPD프로그램을 하고자 할때 그때 예제를 분석해 보세요.

1.HTTP 연결 프로그램

<1>HTML 파일 읽기

HTTP 프로토클을 지원하는 MFC클래스는  CInternetSession 과 CInternetFile 입니다. CInternetSession은 특정 URL과 연결을 시도하는 클래스이며 CInternetFile은 연결된 세션을 컨트롤 하는 인터넷용 파일 핸들러 입니다. 웹브라우저에서는 모든 것이 파이을 읽는 것에 의해서 이루어 지고 있습니다. 네스케이프나 인터넷 익스플로어 같은 웹브라우저로 필자의 홈페이지에 방문하면 처음으로 받는 파일이 index.html입니다. 즉 웹브라우저는 HTML파일을 다운 받은후에 그파일을 분석하여 화면에 그래픽처리를 해주는 것이 전부라고 볼수 있습니다. 파일을 받기 위해서는 어떤 전송 통로를 만들어야 합니다. 이통로를 설정해주는 것이 바로 CInternetSession이며 이통로를 통해서 파일을 받고 그것을 핸들링하는 클래스가 CInternetFile입니다.

특정 URL에 접속을 하고자 할 경우 제일먼저 해야 할 일이 바로 통로 설정입니다.

CInternetSession session;

위와 같이 session이라는 변수를 CInternetSession클래스 형으로 설정을 한다음에

OpenURL 함수에 주소를 설정하면 연결통로를 만들어 줍니다. 예를 들어 필자의 홈페이지 주소 "http://www.zikimi.co.kr"에 접속하고자 한다면 다음과 같이 하면 됩니다.

session.OpenURL("http://www.zikimi.co.kr");

위와 같이 OpenURL를 실행시키면 통로를 만들어주고 이것을 컨트롤할 인터넷 파일 핸들러 클래스 CInterFile 형의 값을 리턴합니다.

CInternetSession session;

CInternetFile* file=NULL;

file=(CInternetFile *) session.OpenURL(□http://www.zikimi.co.kr");

위와 같이 하면 바로 특정 홈페이지 URL에 접속을 하고 인터넷 파일 핸들러를 받게 됩니다. 이제 CInternetFile클래스이 맴버 함수인 SetReadBufferSize 를 이용하여 전송되는 데이터를 받을 임시 버퍼를 설정합니다.

file->SetReadBufferSize(4096);

위와 같이 임시 버퍼를 설정한후에 한라인씩 데이터를 읽고자 한다면 ReadString 함수를 실행하면 됩니다.

CString data;

for(;;)

{

if(!file->ReadString(data))

break;

}

위와 같이하면 data안에 설정된 HTML파일의 정보를 한라인씩 받게 됩니다.

아주 간단하게 인터넷에서 홈페이지를 받을수 있을 겁니다. CInternetSession 과 CInternetFile 클래스는 인터넷 상에서 홈페이지를 받을수 있는 여러 멤버 함수를 제공하고 있습니다. 도움말을 사용하여 이 두함수의 사용법을 참조하세요.

<2>.HTML파일 보기 예제 ExWww

ExWww는 실행 결과는 그림 5-3-1과 같습니다.

(그림 5-3-1)ExWww 실행 결과

URL입력 란에 주소를 입력하고 □설정□버튼을 클릭하면 해당하는 URL에 연력하고 HTML파일 내용을 에디터박스에 출력을 합니다.

ExWww는 AppWizard에서 SDI형으로 ExWwwView가 FormView인 일반적인 프로젝트로 설정하였습니다. □설정□ 버튼을 클릭하면 실행되는 함수가 OnGeturl() 함수입니다. 본예는 OnGeturl()함수가 전부입니다.

//설정 버튼 클릭시

void CExWwwView::OnGeturl()

{

//리소스에서 데이터를 받고

UpdateData(TRUE);

CInternetSession session;

CInternetFile* file=NULL;

try //URL를 열고자 시도

{

file=(CInternetFile *) session.OpenURL(m_strUrlAddress);

}

catch (CInternetException* pEx)//파일을 열지 못하면

{

file =NULL;

AfxMessageBox("인터넷 접근 에러발생");

}

if(file)//파일을 열었다면

{

CString data;

//버퍼 설정

file->SetReadBufferSize(4096);

//에디터 박스와 연결된 CString초기화

m_strUrlData="";

//파일을 읽는다.

for(int i=0;;i++)

{

//한줄을 읽어서

if(!file->ReadString(data))

break;

//에디터박스에 넣는다.

m_strUrlData+=data;

m_strUrlData+="\r\n";

}

//파일 닫기

file->Close();

}

else

{

AfxMessageBox("서버를 찾을수 없음");

}

//화면 갱신

UpdateData(FALSE);

}

<3>웹브라우저를 만들기 위해서는

ExWww 는 HTML 파일을 문자로 출력합니다. 이문자를 해석하여 화면에 출력하면 이것이 바로 웹브라우저 입니다. 필자의 홈페이지 질문란에 이런 웹브라우저를 만드는 방법에 대해서 질문이 있었습니다. 연결은 매우 간단하기 때문에 큰문제가 없을것으로 보고 또한 HTML파일을 읽을수 있으니 큰문제가 없습니다. 그렇다면 다음문제는 무엇일까요? 몇가지 문제에 대한 해결방법을 설명하겠습니다.

1.JPG,GIF파일 읽고 출력

HTML파일 안에는 JPG와 GIF이미지 파일이 있습니다. 즉 다음과 같은 구문이 있는 것이지요.

<IMG SRC="TEST.JPG">

위와 같은 구문이 나오면 TEST.JPG를 HTML파일을 읽는 방법으로 똑같이 읽고 난후에 이것을 출력하면 됩니다. JPG와 GIF출력에 대한 참고 서적은

본책과 Graphics File Formats,C.Wayne Brown and Barry J.Shepherd(Prentice Hall)를 참고 하시면 됩니다.

<4>.구문 처리

HTML파일은 태그문과 데이터로 설정되어 있습니다. 즉 다음과 같이 말입니다.

<HTML>

<HEAD>

<TITLE>예제 HTML</TITLE>

</HEAD>

<BODY>

이것은 예제 입니다.<BR>

</BODY>

</HTML>

즉 □<□과 □>□ 사이에 있는 내용이 명령이고 이명령에 의해 다음에 나오는 데이터가 변경되어 출력됩니다. 그렇다면 "<"를 찾은 다음 그다음 문자를 읽고 문자열 비교를 한다음 명령을 인식하고 그다음 데이터를 그명령에 맞게 출력하면 되겠네요□ 라고 말씀하시는 분들이 있을 것입니다. 물론 기본적으로는 그렇습니다. 그러나 다음과 같은 경우를 보세요.

<TABLE BORDER>

<TR>

<TD><IMG SRC="TEST.GIF">그림<A HREF="MYTEST.HTML>

여기</A></TD>

위와 같은 경우는 테이블안에 첫줄 첫칸에 TEST.GIF를 넣고 그옆에 그림을 그리고 여기를 클릭하면 MYTEST.HTML로 넘어가라는 형태입니다.

명령 안에 명령 또 그안에 명령이 들어 있는 형태 이지요. 이렇게 복잡하게 구성하였을 경우 위와 같은 생각으로 프로그램을 작성한다면 switch()문이 쫘악있고 거기에 또다시 if..else문이 쫘악있고 그러다가 포기를 할것입니다. 구문 해석을 하는 방법을 참조하셔야 합니다. 참고 서적은 Compilers Principles,Techniques,and Tools ,Alfred V.Aho Ravi Sethi Jeffrey D.Ullman 저 ,윤주형,윤정섭,이규형,황병선 공역,(성안당) 책에서 3장 형태소 분석,4장 구문분석,5장 구문 중심 번역 을 참조하시고 자연언어처리,김영택,(교학사) 책의 5장 파싱, 9장 일반 구조조문법을 참조하세요.

<5>.자바 해석

웹브라우저는 자바실행파일을 당연하게 해석을 할수 있어야 합니다. 자바 실행파일은 일종의 스크립트 형식을 띈 실행파일이라서 해석이 쉽습니다. 참고서적보다는  자바를 개발한  Sun 사의 홈페이지를 방문하시면 자바의 구조에 대해서 자세히 나오고 해석하는 방법에 대한 설명서도 있으니 참조를 하세요.

<6>.자바 스크립트 VBScript 와 ActiveX 해석

자바 스크립트 및 VBScrip는 html안에 내장된 명령어에 의해서 구동합니다. 자바 스크립트에 대한 해석방법은 네스케이프 사의 홈페이지를 참조하시고 VBScript와 ActiveX 해석은 VBScript와 ActiveX,SPENCER MILLER LASSESEN 저,(영진출판사) 와 본서를 참조 하시면 됩니다.

어때요? 한 번 만들어 보심이 어떨까요? 국내에서 만든 웹브라우저가 아직은 없잖아요!

(주의!)

ExWww프로그램에서 인터넷 함수를 사용하기 위해서는

#include <afxinet.h>

를 삽입해야 합니다.

(주의 끝)

<7>프로그램 소스

(프로그램 소스시작)

// ExWwwView.h : interface of the CExWwwView class

//

/////////////////////////////////////////////////////////////////////////////

#if !defined(AFX_EXWWWVIEW_H__3EDA632E_FA7D_11D0_A7D7_0000E8D03CE2__INCLUDED_)

#define AFX_EXWWWVIEW_H__3EDA632E_FA7D_11D0_A7D7_0000E8D03CE2__INCLUDED_

#if _MSC_VER >= 1000

#pragma once

#endif // _MSC_VER >= 1000

class CExWwwView : public CFormView

{

protected: // create from serialization only

CExWwwView();

DECLARE_DYNCREATE(CExWwwView)

public:

//{{AFX_DATA(CExWwwView)

enum { IDD = IDD_EXWWW_FORM };

CString	m_strUrlAddress;

CString	m_strUrlData;

//}}AFX_DATA

// Attributes

public:

CExWwwDoc* GetDocument();

// Operations

public:

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CExWwwView)

public:

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnPrint(CDC* pDC, CPrintInfo*);

//}}AFX_VIRTUAL

// Implementation

public:

virtual ~CExWwwView();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Generated message map functions

protected:

//{{AFX_MSG(CExWwwView)

afx_msg void OnGeturl();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#ifndef _DEBUG  // debug version in ExWwwView.cpp

inline CExWwwDoc* CExWwwView::GetDocument()

{ return (CExWwwDoc*)m_pDocument; }

#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_EXWWWVIEW_H__3EDA632E_FA7D_11D0_A7D7_0000E8D03CE2__INCLUDED_)

// ExWwwView.cpp : implementation of the CExWwwView class

//

#include "stdafx.h"

#include "ExWww.h"

#include "ExWwwDoc.h"

#include "ExWwwView.h"

#include <afxinet.h>

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CExWwwView

IMPLEMENT_DYNCREATE(CExWwwView, CFormView)

BEGIN_MESSAGE_MAP(CExWwwView, CFormView)

//{{AFX_MSG_MAP(CExWwwView)

ON_BN_CLICKED(IDC_GETURL, OnGeturl)

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CExWwwView construction/destruction

CExWwwView::CExWwwView()

: CFormView(CExWwwView::IDD)

{

//{{AFX_DATA_INIT(CExWwwView)

m_strUrlAddress = _T("");

m_strUrlData = _T("");

//}}AFX_DATA_INIT

// TODO: add construction code here

}

CExWwwView::~CExWwwView()

{

}

void CExWwwView::DoDataExchange(CDataExchange* pDX)

{

CFormView::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CExWwwView)

DDX_Text(pDX, IDC_URLADDRESS, m_strUrlAddress);

DDX_Text(pDX, IDC_URLDATA, m_strUrlData);

//}}AFX_DATA_MAP

}

BOOL CExWwwView::PreCreateWindow(CREATESTRUCT& cs)

{

// TODO: Modify the Window class or styles here by modifying

//  the CREATESTRUCT cs

return CFormView::PreCreateWindow(cs);

}

/////////////////////////////////////////////////////////////////////////////

// CExWwwView printing

BOOL CExWwwView::OnPreparePrinting(CPrintInfo* pInfo)

{

// default preparation

return DoPreparePrinting(pInfo);

}

void CExWwwView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add extra initialization before printing

}

void CExWwwView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add cleanup after printing

}

void CExWwwView::OnPrint(CDC* pDC, CPrintInfo*)

{

// TODO: add code to print the controls

}

/////////////////////////////////////////////////////////////////////////////

// CExWwwView diagnostics

#ifdef _DEBUG

void CExWwwView::AssertValid() const

{

CFormView::AssertValid();

}

void CExWwwView::Dump(CDumpContext& dc) const

{

CFormView::Dump(dc);

}

CExWwwDoc* CExWwwView::GetDocument() // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CExWwwDoc)));

return (CExWwwDoc*)m_pDocument;

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// CExWwwView message handlers

//설정 버튼 클릭히

void CExWwwView::OnGeturl()

{

//리소스에서 데이터를 받고

UpdateData(TRUE);

CInternetSession session;

CInternetFile* file=NULL;

try //URL를 열고자 시도

{

file=(CInternetFile *) session.OpenURL(m_strUrlAddress);

}

catch (CInternetException* pEx)//파일을 열지 못하면

{

file =NULL;

AfxMessageBox("인터넷 접근 에러발생");

}

if(file)//파일을 열었다면

{

CString data;

//버퍼 설정

file->SetReadBufferSize(4096);

//에디터 박스와 연결된 CString초기화

m_strUrlData="";

//파일을 읽는다.

for(int i=0;;i++)

{

//한줄을 읽어서

if(!file->ReadString(data))

break;

//에디터박스에 넣는다.

m_strUrlData+=data;

m_strUrlData+="\r\n";

}

//파일 닫기

file->Close();

}

else

{

AfxMessageBox("서버를 찾을수 없음");

}

//화면 갱신

UpdateData(FALSE);

}

2.FTP 연결 프로그램

FTP 로 연결하여 파일을 받고 파일을 업로드 하는 등의 기능을 하는 클래스는 다음 3개로 볼수 있습니다.

CInternetSession : FTP연결 통로를 구성하는 클래스

CFtpConnection : FTP명령문 컨트롤 클래스

CFtpFileFind : FTP 파일 리스트 검색 클래스

FTP는 LAN 소켓 방법으로 포트번호 21에 의해 연결되고 명령문에 의해 파일 리스트를 보며 특정 파일을 다운 업로드 할수 있는 프로토클입니다.

제일 먼저 연결을 하는 클래스가 바로 CInternetSession이고 이것에 의해서 명령문을 전달하는 클래스가 CFtpConnection이면 현재 서버안에 존재하는 파일들의 정보를 얻는 클래스가 CFtpFileFind 클래스 입니다.

<1>FTP연결

FTP는 다음과 같이 연결합니다.

CInternetSession session;

CFtpConnection *connect;

//Anonymous 로 연결할경우

connect= session.GetFtpConnection(m_strAddress);

//자신의 Username와 비밀번호로 연결할 경우

connect= session.GetFtpConnection(m_strAddress,Username,Password);

즉 CInternetSession클래스의 내부함수 GetFtpConnection에 주소를 인자로 설정하여 실행하여 넘겨받은 CFtpConnection클래스 형을 넘겨 받으면 됩니다. 보통 FTP를 사용할 경우 서버에 손님으로 방문하고자 할 경우 즉 Anonymous로 방문하고자 할경우에는 주소만 설정하고 자신의 유저명과 비밀번호로 방문하고자 할경우에는 유저명과 비밀번호를 설정하여 주면 됩니다.

<2>연결된 서버안의 파일 리스트 보기

서버에 연결하여 현재 파일 리스트를 보기 위해서는 연결된 서버의 현재 디렉토리가 어느곳인지 알아야 합니다. 이때 사용하는 함수는 CFtpConnection클래스의 맴버 함수인 GetCurrentDirectory를 사용하면 됩니다.

CString szDir

connect->GetCurrentDirectory(szDir);

다음 CFtpConnection클래스형의 변수이 connect를 이용하여 CFtpFileFind 클래스 형의 변수를 설정합니다.

CFtpFileFind  m_pFileFind=new CFtpFileFind(connect);

위와 같이 설정한후에 검색할 파일 명을 설정합니다. 만일 전체 리스틀 보고자 한다면 다음과 같이 하면 됩니다.

m_pFileFind->FindFile(□*□);

위와 같이 한다음 FindNextFile 함수를 이용하여 파일 명에 접근합니다.

m_pFileFind->FindNextFile();

다음 위의  GetFileName() 함수를 이용하여 파일명을 얻습니다.

CString szFileName;

m_pFileFind->GetFileName(szFileName);

szFileName이 디렉토리 인가 파일명인가를 알고자 한다면  IsDirectory() 함수를 이용합니다.

if(m_pFileFind->IsDirectory())

{

//디렉토리임

}

else

{

//파일 임

}

FindNextFile()함수와 GetFileName()함수를 쌍으로 계속 반복을 하면서 현재 서버의 디렉토리안의 파일 이름을 얻을수 있습니다. FindNextFile함수는 다음으로 이동을 하지 못했을 경우 FALSE값을 리턴합니다. 반복을 하다가 FindNextFile함수의 리턴값이 0이면 탈출을 하면 됩니다.

BOOL bBreak=TRUE;

while(bBreak)

{

bBreak=m_pFileFind->FindNexFile();

m_pFileFind->GetFileName();

}

<3>파일 보내기

클라이언트 컴퓨터에 있는 특정 파일을 서버 컴퓨터에 보내는 함수는 CFtpConnection 의 PutFile함수입니다. 예를 들어서 현재 □C::\temp\data.txt"를 서버에 보내고자 한다면 다음과 같이 하면 됩니다.

connect->PutFile(□C:\\temp\\data.txt","data.txt");

앞에 인자는 클라이언트에 설정된 파일명이고 뒤의 인자는 서버에 설정할 파일 명입니다. 위와 같이 실행하면 data.txt라는 파일이 서버로 전송합니다. 서버에 전송할 파일명은 경로명을 설정할 필요는 없으나 클라이언트에 있는 파일명은 경로명을 정확하게 설정하여 주어야 합니다.

<4>파일받기

서버에 있는 특정 파일을 클라이언트로 다운 받을 경우 PurFile과 대응되는 GetFile라는 함수가 있습니다. 인자의 순서도 PutFile과는 역순입니다.

connect->GetFile("user/sylee/data.txt","data.txt");

파일을 받고자 할경우에는 첫 번째 인자 즉 서버 안에 있는 파일명은 전체 경로를 전부 설정해 주어야 합니다.

<5>.FTP 컨트롤 프로그램 ExFtp

ExFtp는 FTP를 컨트롤 하는 프로그램으로서 실행 결과는 그림 5-3-2와 같습니다.

(그림 5-3-2) ExFtp 실행결과

주소 입력란에 주소를 입력하고  User에 사용자 명을 비밀번호 입력란에 비밀번호를 입력하고 연결버튼을 클릭하면 리스트 박스에 현재 서버안에 있는 파일 리스트가 나타납니다. 디렉토리일 경우 파일명 끝에 □/□ 문자가 삽입되어 나타납니다. 리스트 박스에서 디렉토리명을 더블 클릭하면 그 디렉토리로 이동을 하고 파일명을 선택한후에 □복사□버튼을 클릭하면 파일을 다운 받을수 있으며 □업로드□ 버튼을 클릭하면 파일을 업로드 할수 있습니다.

본프로그램은 AppWizard를 이용하여 SDI 형으로 만들고 ExFtpView가 FormView인 형태로 제작하였습니다.

<6>FTP연결하기

ExFtpView는 FormView로 3개의 에디터박스와 한 개의 리스트 박스 가 있습니다.

이것과 FTP를 구동하는 클래스 3개를 ExFtpView의 헤더에 다음과 같이 삽입하였습니다.

CListBox	m_listDir;//서버 디렉토리의 파일 리스트 설정 리스트 박스

CString	m_strAddress;//FTP 주소 입력 에디터 박스와 연결된 변수

CFtpFileFind *m_pFileFind;//FTP 파일 검색 클래스

CString szDir;//현재 서버 디렉토리 설정 변수

CString	m_strUser;//사용자명 입력 변수

CString	m_strPassword;//비밀번호 입력변수

CInternetSession session;//인터넷 세션 클래스

CFtpConnection *connect;//Ftp 명령 연결 컨트롤 클래스

□연결□ 버튼을 클릭하면 FTP를 연력하고 연결된 디렉토리의 파일 정보를 리스트 박스에 기록합니다. 이 내용이 실행되는 함수는 OnConnect()  입니다.

//연결 버튼 클릭시

void CExFtpView::OnConnect()

{

//자원에서 입력받은 정보 얻어서

UpdateData(TRUE);

try

{

//커서를 모래시계로 전환

SetCursor(LoadCursor(NULL, IDC_WAIT));

//유저명이 없으면

if(m_strUser.GetLength()==0)

connect= session.GetFtpConnection(m_strAddress);

//유저명이 있으면

else

connect=

session.GetFtpConnection(m_strAddress,m_strUser,m_strPassword);

}//예외 적용

catch (CInternetException *pEX)

{

AfxMessageBox("인터넷 연결이 안됩니다.");

}

if(connect)//연결이 되면

{

//현재 서버 디렉토리를 받는다.

connect->GetCurrentDirectory(szDir);

szDir+="/";

//m_pFileFind가 이미 설정 되었으면 해제

if(m_pFileFind)

delete m_pFileFind;

//m_pFileFine를 새로 설정

m_pFileFind=new CFtpFileFind(connect);

//리스트 박스안에 있는 데이터를 지우고

m_listDir.ResetContent();

CString data;

//파일을 찾는다.

m_pFileFind->FindFile(szDir);

BOOL bContinue=TRUE;

while(bContinue)

{

//파일 명을 얻는다.

bContinue=m_pFileFind->FindNextFile();

data=m_pFileFind->GetFileName();

//디렉토리이면 끝에 "/"를 삽입

if(m_pFileFind->IsDirectory())

data+='/';

//리스트 박스에 넣는다.

m_listDir.AddString(data);

}

}

else

{

AfxMessageBox("주소를 찾을수 없습니다.");

}

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

<7>디렉토리 전환

리스트 박스에서 특정 디렉토리 파일을 더블클릭하면 해당 디렉토리로 전환해야 합니다. 이내용이 연결된 함수는 OnDblclkList1() 입니다.

//디렉토리 이동

void CExFtpView::OnDblclkList1()

{

UpdateData(FALSE);

//리스트 박스에서 파일 명을 얻는다.

int num=m_listDir.GetCurSel();

CString Dir;

m_listDir.GetText(num,Dir);

//만일 Dir이 "../"이면 상위 디렉토리로 이동

//해야 함으로 현재 디렉토리에서 "/"다음의 데이터를

//잘라낸다.

if(Dir=="../")

{

char temp[80];

sprintf(temp,"%s",szDir);

temp[strlen(temp)-1]=NULL;

int len=strlen(temp)-1;

for(int i=len;i>0;i--)

{

if(temp[i]=='/')

{

temp[i+1]=NULL;

break;

}

}

szDir=temp;

}

else

szDir+=Dir;//이동할 디렉토리명을 현재 디렉토리에 삽입

//디렉토리를 전환한다.

if(!connect->SetCurrentDirectory(szDir))

{

//전환을 실패하면

//현재 디렉토리명으로 복구

connect->GetCurrentDirectory(szDir);

szDir+="/";

AfxMessageBox("디렉토리 이동이 불가능합니다.");

return;

}

//모래시계 커서로 변경

SetCursor(LoadCursor(NULL, IDC_WAIT));

//리스트 박스안에 데이터를 지우고

m_listDir.ResetContent();

CString data;

//현재 디렉토리 안에 있는 파일을

//리스트 디렉토리에 넣는다.

m_pFileFind->FindFile(szDir);

BOOL bContinue=TRUE;

while(bContinue)

{

bContinue=m_pFileFind->FindNextFile();

data=m_pFileFind->GetFileName();

if(m_pFileFind->IsDirectory())

data+='/';

m_listDir.AddString(data);

}

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

<8>파일 복사

□복사□ 버튼을 클릭하면 리스트 박스에서 선택한 파일을 클라이언트 컴퓨터의 특정 디렉토리로 복사합니다. 이때 실행되는 함수는 OnCopy()  입니다.

//파일 복사시

void CExFtpView::OnCopy()

{

UpdateData(FALSE);

//리스트 박스에서 파일명을 얻고

int num=m_listDir.GetCurSel();

char temp[512];

m_listDir.GetText(num,temp);

//디렉토리이면 복사를 하지 않는다.

if(temp[strlen(temp)-1]=='/')

{

AfxMessageBox("디렉토리는 복사할수 없습니다.");

return;

}

CString downData;

downData=szDir;

downData+=temp;

//현재 컴퓨터에 설정할 디렉토리와 파일명을

//얻기 위해서 파일 대화상자 실행

CFileDialog	dlg (TRUE,NULL,temp, OFN_HIDEREADONLY,

_T("모든파일 (*.*)|*.*|"),

this);

if(dlg.DoModal()==IDOK)

{

SetCursor(LoadCursor(NULL, IDC_WAIT));

//파일을 복사한다.

connect->GetFile(downData,dlg.GetPathName());

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

}

<9>파일 업로드

□업로드□ 버튼을 클릭하면 파일 대화상자가 나타나고 특정 파일을 클릭하면 그파일이 서버로 전달됩니다. 이내용이 실행되는 함수는 OnUpload() 입니다.

//파일 업로드

void CExFtpView::OnUpload()

{

//업로드할 파일명을 설정하기 위한 파일 대화상자 tlfgod

CFileDialog	dlg (FALSE,NULL,NULL, OFN_HIDEREADONLY,

_T("모든파일 (*.*)|*.*|"),

this);

if(dlg.DoModal()==IDOK)

{

SetCursor(LoadCursor(NULL, IDC_WAIT));

//파일을 업로드한다.

connect->PutFile(dlg.GetPathName(),dlg.GetFileName());

//리스트 박스에 데이터를 다시 기록 한다.

m_listDir.ResetContent();

CString data;

m_pFileFind->FindFile(szDir);

BOOL bContinue=TRUE;

while(bContinue)

{

bContinue=m_pFileFind->FindNextFile();

data=m_pFileFind->GetFileName();

if(m_pFileFind->IsDirectory())

data+='/';

m_listDir.AddString(data);

}

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

}

(주의!)

ExFpt프로그램에서 인터넷 함수를 사용하기 위해서는 StdAfx.h에

#include <afxinet.h>

를 삽입해야 합니다.

(주의 끝)

<10>프로그램 소스

(프로그램 소스)

class CExFtpView : public CFormView

{

protected: // create from serialization only

CExFtpView();

DECLARE_DYNCREATE(CExFtpView)

public:

//{{AFX_DATA(CExFtpView)

enum { IDD = IDD_EXFTP_FORM };

CListBox	m_listDir;//서버 디렉토리의 파일 리스트 설정 리스트 박스

CString	m_strAddress;//FTP 주소 입력 에디터 박스와 연결된 변수

CFtpFileFind *m_pFileFind;//FTP 파일 검색 클래스

CString szDir;//현재 서버 디렉토리 설정 변수

CString	m_strUser;//사용자명 입력 변수

CString	m_strPassword;//비밀번호 입력변수

//}}AFX_DATA

// Attributes

public:

CExFtpDoc* GetDocument();

CInternetSession session;//인터넷 세션 클래스

CFtpConnection *connect;//Ftp 명령 연결 컨트롤 클래스

// Operations

public:

// Overrides

// ClassWizard generated virtual function overrides

//{{AFX_VIRTUAL(CExFtpView)

public:

virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

protected:

virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support

virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

virtual void OnPrint(CDC* pDC, CPrintInfo*);

//}}AFX_VIRTUAL

// Implementation

public:

virtual ~CExFtpView();

#ifdef _DEBUG

virtual void AssertValid() const;

virtual void Dump(CDumpContext& dc) const;

#endif

protected:

// Generated message map functions

protected:

//{{AFX_MSG(CExFtpView)

afx_msg void OnConnect();

afx_msg void OnDblclkList1();

afx_msg void OnCopy();

afx_msg void OnUpload();

//}}AFX_MSG

DECLARE_MESSAGE_MAP()

};

#ifndef _DEBUG  // debug version in ExFtpView.cpp

inline CExFtpDoc* CExFtpView::GetDocument()

{ return (CExFtpDoc*)m_pDocument; }

#endif

/////////////////////////////////////////////////////////////////////////////

//{{AFX_INSERT_LOCATION}}

// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_EXFTPVIEW_H__3EDA6342_FA7D_11D0_A7D7_0000E8D03CE2__INCLUDED_)

// ExFtpView.cpp : implementation of the CExFtpView class

//

#include "stdafx.h"

#include "ExFtp.h"

#include "ExFtpDoc.h"

#include "ExFtpView.h"

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CExFtpView

IMPLEMENT_DYNCREATE(CExFtpView, CFormView)

BEGIN_MESSAGE_MAP(CExFtpView, CFormView)

//{{AFX_MSG_MAP(CExFtpView)

ON_BN_CLICKED(IDC_CONNECT, OnConnect)

ON_LBN_DBLCLK(IDC_LIST1, OnDblclkList1)

ON_BN_CLICKED(IDC_COPY, OnCopy)

ON_BN_CLICKED(IDC_UPLOAD, OnUpload)

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND(ID_FILE_PRINT, CFormView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_DIRECT, CFormView::OnFilePrint)

ON_COMMAND(ID_FILE_PRINT_PREVIEW, CFormView::OnFilePrintPreview)

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////

// CExFtpView construction/destruction

CExFtpView::CExFtpView()

: CFormView(CExFtpView::IDD)

{

//{{AFX_DATA_INIT(CExFtpView)

m_strAddress = _T("");

m_strUser = _T("");

m_strPassword = _T("");

//}}AFX_DATA_INIT

// TODO: add construction code here

connect =NULL;

m_pFileFind=NULL;

}

CExFtpView::~CExFtpView()

{

}

void CExFtpView::DoDataExchange(CDataExchange* pDX)

{

CFormView::DoDataExchange(pDX);

//{{AFX_DATA_MAP(CExFtpView)

DDX_Control(pDX, IDC_LIST1, m_listDir);

DDX_Text(pDX, IDC_ADDRESS, m_strAddress);

DDX_Text(pDX, IDC_EDIT1, m_strUser);

DDX_Text(pDX, IDC_EDIT2, m_strPassword);

//}}AFX_DATA_MAP

}

BOOL CExFtpView::PreCreateWindow(CREATESTRUCT& cs)

{

// TODO: Modify the Window class or styles here by modifying

//  the CREATESTRUCT cs

return CFormView::PreCreateWindow(cs);

}

/////////////////////////////////////////////////////////////////////////////

// CExFtpView printing

BOOL CExFtpView::OnPreparePrinting(CPrintInfo* pInfo)

{

// default preparation

return DoPreparePrinting(pInfo);

}

void CExFtpView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add extra initialization before printing

}

void CExFtpView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

// TODO: add cleanup after printing

}

void CExFtpView::OnPrint(CDC* pDC, CPrintInfo*)

{

// TODO: add code to print the controls

}

/////////////////////////////////////////////////////////////////////////////

// CExFtpView diagnostics

#ifdef _DEBUG

void CExFtpView::AssertValid() const

{

CFormView::AssertValid();

}

void CExFtpView::Dump(CDumpContext& dc) const

{

CFormView::Dump(dc);

}

CExFtpDoc* CExFtpView::GetDocument() // non-debug version is inline

{

ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CExFtpDoc)));

return (CExFtpDoc*)m_pDocument;

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// CExFtpView message handlers

//연결 버튼 클릭시

void CExFtpView::OnConnect()

{

//자원에서 입력받은 정보 얻어서

UpdateData(TRUE);

try

{

//커서를 모래시계로 전환

SetCursor(LoadCursor(NULL, IDC_WAIT));

//유저명이 없으면

if(m_strUser.GetLength()==0)

connect= session.GetFtpConnection(m_strAddress);

//유저명이 있으면

else

connect= session.GetFtpConnection(m_strAddress,m_strUser,m_strPassword);

}//예외 적용

catch (CInternetException *pEX)

{

AfxMessageBox("인터넷 연결이 안됩니다.");

}

if(connect)//연결이 되면

{

//현재 서버 디렉토리를 받는다.

connect->GetCurrentDirectory(szDir);

szDir+="/";

//m_pFileFind가 이미 설정 되었으면 해제

if(m_pFileFind)

delete m_pFileFind;

//m_pFileFine를 새로 설정

m_pFileFind=new CFtpFileFind(connect);

//리스트 박스안에 있는 데이터를 지우고

m_listDir.ResetContent();

CString data;

//파일을 찾는다.

m_pFileFind->FindFile(szDir);

BOOL bContinue=TRUE;

while(bContinue)

{

//파일 명을 얻는다.

bContinue=m_pFileFind->FindNextFile();

data=m_pFileFind->GetFileName();

//디렉토리이면 끝에 "/"를 삽입

if(m_pFileFind->IsDirectory())

data+='/';

//리스트 박스에 넣는다.

m_listDir.AddString(data);

}

}

else

{

AfxMessageBox("주소를 찾을수 없습니다.");

}

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

//디렉토리 이동

void CExFtpView::OnDblclkList1()

{

UpdateData(FALSE);

//리스트 박스에서 파일 명을 얻는다.

int num=m_listDir.GetCurSel();

CString Dir;

m_listDir.GetText(num,Dir);

//만일 Dir이 "../"이면 상위 디렉토리로 이동

//해야 함으로 현재 디렉토리에서 "/"다음의 데이터를

//잘라낸다.

if(Dir=="../")

{

char temp[80];

sprintf(temp,"%s",szDir);

temp[strlen(temp)-1]=NULL;

int len=strlen(temp)-1;

for(int i=len;i>0;i--)

{

if(temp[i]=='/')

{

temp[i+1]=NULL;

break;

}

}

szDir=temp;

}

else

szDir+=Dir;//이동할 디렉토리명을 현재 디렉토리에 삽입

//디렉토리를 전환한다.

if(!connect->SetCurrentDirectory(szDir))

{

//전환을 실패하면

//현재 디렉토리명으로 복구

connect->GetCurrentDirectory(szDir);

szDir+="/";

AfxMessageBox("디렉토리 이동이 불가능합니다.");

return;

}

//모래시계 커서로 변경

SetCursor(LoadCursor(NULL, IDC_WAIT));

//리스트 박스안에 데이터를 지우고

m_listDir.ResetContent();

CString data;

//현재 디렉토리 안에 있는 파일을

//리스트 디렉토리에 넣는다.

m_pFileFind->FindFile(szDir);

BOOL bContinue=TRUE;

while(bContinue)

{

bContinue=m_pFileFind->FindNextFile();

data=m_pFileFind->GetFileName();

if(m_pFileFind->IsDirectory())

data+='/';

m_listDir.AddString(data);

}

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

//파일 복사시

void CExFtpView::OnCopy()

{

UpdateData(FALSE);

//리스트 박스에서 파일명을 얻고

int num=m_listDir.GetCurSel();

char temp[512];

m_listDir.GetText(num,temp);

//디렉토리이면 복사를 하지 않는다.

if(temp[strlen(temp)-1]=='/')

{

AfxMessageBox("디렉토리는 복사할수 없습니다.");

return;

}

CString downData;

downData=szDir;

downData+=temp;

//현재 컴퓨터에 설정할 디렉토리와 파일명을

//얻기 위해서 파일 대화상자 실행

CFileDialog	dlg (TRUE,NULL,temp, OFN_HIDEREADONLY,

_T("모든파일 (*.*)|*.*|"),

this);

if(dlg.DoModal()==IDOK)

{

SetCursor(LoadCursor(NULL, IDC_WAIT));

//파일을 복사한다.

connect->GetFile(downData,dlg.GetPathName());

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

}

//파일 업로드

void CExFtpView::OnUpload()

{

//업로드할 파일명을 설정하기 위한 파일 대화상자 tlfgod

CFileDialog	dlg (FALSE,NULL,NULL, OFN_HIDEREADONLY,

_T("모든파일 (*.*)|*.*|"),

this);

if(dlg.DoModal()==IDOK)

{

SetCursor(LoadCursor(NULL, IDC_WAIT));

//파일을 업로드한다.

connect->PutFile(dlg.GetPathName(),dlg.GetFileName());

//리스트 박스에 데이터를 다시 기록 한다.

m_listDir.ResetContent();

CString data;

m_pFileFind->FindFile(szDir);

BOOL bContinue=TRUE;

while(bContinue)

{

bContinue=m_pFileFind->FindNextFile();

data=m_pFileFind->GetFileName();

if(m_pFileFind->IsDirectory())

data+='/';

m_listDir.AddString(data);

}

SetCursor(LoadCursor(NULL, IDC_ARROW));

}

}

(프로그램 소스끝)