일단 인터넷 프로그래밍을 하기전에 winsock.h를 include하시길 바랍니다.
인터넷에서 서로 정보를 공유하는데 서로의 문(門)역할을 하는것으로 Socket이라는 것이 있다.
FTP서버를 접속할때 주소치고 들어갈수 있는것은 그곳의 소켓이 열려있기 때문이다.
설명하기 힘들군... 걍 대충 컴퓨터간의 문 이라고 생각해라. 강좌 첨쓰는거라 설명어케하는지
몰겠다. 그리구 이 모든것에서는 MFC에서만 된다. API가지구 식은땀 흘리지 말라. 그리구
아래꺼 외울라구 하지말구 걍 보며 따라해라. 안외워진다. 그리구 여기에 오타가 있을지도
--; 있으면 망하는데. 어쨋든 있으면 email로... 이거 쓰고싶어서 쓴게 아니라 협박 받아서
쓰는 거니까 넘 많은걸 바라지 마시고 묻지도 마시오~ -.-

일단 소켓을 열어두어야한다. Create()함수를 쓴다

CSocket Socket;
Socket.Create( 포트번호 );

여기서 포트번호에 열고싶은 번호를 쓴다.
예를들어 FTP서버라면 21번을 쓴다. 많은 프로그램에서 포트를 쓰고있기때문에
약간 흔하지 않은 포트번호를 쓰는것도 좋다.
이제는 다른 곳으로 접속을 하기전에 SOCKADDR_IN으로 접속할 곳의 정보를 제공한다.
설명이 엉성하징... 여기서 SOCKADDR_IN은 winsock.h를 include하지 않았다면 에러난다.
이 아래서 Cokenburger는 아무걸로나 대체해도 된다. 헷갈리지 않도록 색깔로 표시를 했음.

SOCKADDR_IN Cokenburger
memset(&Cokenburger, 0, sizeof (SOCKADDR_IN));
Cokenburger.sin_family=AF_INET;
Cokenburger.sin_port=htons(123); // 포트번호
Cokenburger.sin_addr.s_addr=inet_addr("123.123.123.1"); // IP 주소

이젠 Connect()함수를 이용해서 접속만 하면된다.

if(Socket.Connect((SOCKADDR)
&Cokenburger,sizeof(SOCKADDR_IN)) // 만약 접속이 되었으면
AfxMessageBox("접속 성공이당!");
else
AfxMessageBox("접속 실패당-.-");

아참 또한가지 알아두면 좋은게 있다. 도멘네임에서 IP어드레스를 구하는 것이다.
예를들어 ftp.microsoft.com은 207.46.133.140이다 (맞나?)

HOSTENT *Cokenburger_HostName;
Cokenburger_HostName=gethostbyname("telnet.cokenburger.com"); // 여기다가 도멘네임을
char *Cokenburger_IPaddress = (char *)inetntoa(*(LPIN_ADDR)*(Cokenburger_HostName -> h_addr_list));
// Cokenburger_IPaddress에 IP주소가 실림흠......

그러면 남이 여기로 접속을 하려고 하면 어떻게 받을까. Listen()함수를 쓰면 된다.

역시 MFC가 다 해놔서 정말 간단하다.

if(Socket.Listen())
AfxMessageBox(" 어떤넘이 접속했어 ");
else
AfxMessageBox(" 소켓 에러당 ");

이 Listen()함수는 루프를 돌면서 어떤넘이 접속을 하거나 소켓이 빠가질때까지 계속 돌기 때문에
아주 유용하다.

이제 두번째 CSocket 객체를 맹글어야 한다. 아까 맹근 CSocket객체는 Listen()함수로 더 많은 콜을

받을때 쓸 수가 있다. 여기선 만들때 Accept()함수를 쓴다. 접속 허용하는데 쓰는것이다.
두번째 CSocket으로 접속을 허용한다.

CSocket SecondSocket;
if(Socket.Accept(SecondSocket))
AfxMessageBox(" 접속 허용했당.");
else
AfxMessageBox(" 실패당.");

이젠 데이타를 주고받자
이런식으로 하면 된다. 엄청나게 간단하다

(받기)

int nBytesRead; //받은 것의 바이트수
char cbBuffer[2000]; // 2000바이트의 버퍼 준비다.
nBytesRead=SecondSocket.Receive(cbBuffer, sizeof(cbBuffer));
//버퍼에다가 데이타를 받구 nBytesRead에다가 바이트수를

이제 cbBuffer를 보면 받은 데이타가 있을꺼다.

(주기)

int nBytesWritten; // 쓸것의 바이트수
static char szMessage[]="안녕 소켓으로 보내구 있다. 하하!"); //보낼 것
nBytesWritten = SecondSocket.Send ( szMessage, sizeof(szMessage)); // 보내구 nBytes.Written에 바이트수를

/**************************************************/
// 서버측에서 파일을 전송하는 코드부분
//*************************************************/

// 우리가 사용할 포트를 정의한다. 이 값은 맘대로 사용해도 되지만, 대개 1000 이상
의 포트 번호를 사용하자.
#define PORT 30000

// 맨처음 접속을 대기할 소켓을 생성한다.
AfxInitSocket(NULL);

CAsyncSocket listenSoc;
listenSoc.Create(PORT);

// 그리고는 접속요청을 기다리자.
listenSoc.Listen();

// 접속요청이 왔다면 받아들이자.
CSocket acceptSoc;  // 이 소켓은 Create를 호출하면 안된다.
listenSoc.Accept(&acceptSoc);

// 이제부터 클라이언트와 대화하는 것은 온전히 acceptSoc의 소관이다.
// 전송할 파일을 열자
CFile sourceFile;
sourceFile.Open((LPCTSTR)strFileName, CFile::modeRead | CFile::typeBinary);
// strFileName은 CString 객체로 파일의 이름을 가지고 있다.

// 파일을 전송하기 전에 파일이름을 클라이언트에게 알려줘야 한다. 
// 그래야 클라이언트는 전송받은 파일을 이름을 바꾸지 않고 정확히 쓸 것이다.
int nNameLen = strFileName.GetLength(); // 파일이름의 길이를 저장한다.

acceptSoc.Send(&nNameLen, 4); // 파일 이름의 길이를 전달한다.
acceptSoc.Send((LPCTSTR)strFileName, nNameLen); // 파일 이름을 전달한다.
// 데이터를 위한 임시 버퍼을 잡자.
byte * data = new byte[4096];
DWORD dwRead;
// 파일을 읽고 소켓으로 전송하자.
do
{
  dwRead = sourceFile.Read(data, 4096);
  acceptSoc.Send(data, dwRead);
}
while(dwRead > 0);
/* 위의 코드는 파일의 길이를 4k 바이트씩 잘라서 전송합니다. 소켓의 디폴트 버퍼크
기는 8k이지만, 파일의 전체를 한번에 읽어서 전송하면, 8k가 초과되는 용량에 대해서
는 데이터가 손상되지 않으리라 보장할 수 없습니다. CFile객체의 Read함수는 인수로 
지정된 바이트 수만큼 읽지 않을 수도 있습니다. 하지만 최대로 읽어들이는 양은 인수
로 전달된 바이트수를 초과하지는 않습니다. 따라서 읽어들인 양이 어느정도인지 
dwRead에 저장하고 그 크기를 소켓의 Send함수에 전달해 주어야 하는 것입니다. 소켓
의 Send함수 역시, 지정된 사이즈를 전부 한번에 전송하지 않을 수도 있습니다. 전송
당시의 TCP망이 속도가 저속이면 인수로 지정된 양보다 작은 양을 전송하게 되지만, 
그것은 TCP가 알아서 추가 전송을 할 것이므로 위 코드의 루프에서는 신경써주지 않아
도 됩니다. */

// 메모리를 해제하고 파일핸들을 닫는다
delete data;
sourceFile.Close();


/***************************************/
// 클라이언트에서 파일을 받는 부분
/***************************************/

// 포트를 정의하는데, 서버측과 같은 포트이어야 한다.
#define PORT 30000

// 소켓을 초기화 한다.
AfxInitSocket(NULL);

// 소켓을 만들자
CSocket connectSoc;
connectSoc.Create(); // 여기서는 인수를 전달하지 않는다

// 접속을 요청하자
connectSoc.Connect("210.120.150.111", PORT);
/* Connect함수의 첫번째 인자는 서버측 컴퓨터의 IP주소이다. 이것은 (.)을 찍는 방
식으로 써도 되고, 도메인네임으로 써도 된다.*/
if(connectSoc.GetLastError() == 0) // 접속에 실패하였다면..
{
  MessageBox("접속에 실패하였습니다");
  // 기타 접속실패 처리
  connectSoc.Close();
  return;
}

// 접속에 성공했다면 데이터를 받아 들이자
char *strFileName;
int nNameLen;

connectSoc.Receive(&nNameLen, 4);
connectSoc.Receive(strFileName, nNameLen);

CFile targetFile;
targetFile.Open(strFileName, CFile::modeCreate | CFile::modeWrite | 
CFile::typeBinary);

byte *data = new byte[4096];
DWORD dwRead;

do
{
  dwRead = connectSoc.Receive(data, 4096);
  targetFile.Write(data, dwRead);
}
while(dwRead > 0);

delete data;
targetFile.Close();

위의 코드는 가장 핵심적인 기능만 구현되어 있습니다. 실제로는 이 코드를 애플리케
이션에 붙이고 실행하면 CPU타임을 독차지 하게 되어 파일 전송이 완료되기 까지 사용
자에게 응답하지 않습니다. 용량이 큰 파일을 전송할 경우에는 전송시간이 걸릴 것이
므로, 사용자는 다운된 줄 알고 프로그램을 죽일 수도 있기 때문에 골칫거리가 아닐 
수 없습니다. 또, 전송받는 부분에서 상황에 따라 무한루프에 빠지는 경우도 있는데, 
전송받은 총량과 전송받아야 할 량을 비교해서 루프를 탈출하는 코드가 추가 되어야
만 완전해 집니다.

정리가 매우 잘 되어있습니다

+ Recent posts