실행 시간 클래스 정보
프로그램 실행 중 객체 정보를 알아낸다.

1단계
DECLARE_DYNAMIC, IMPLEMENT_DYNAMIC
실행 시간 클래스 정보
사용예
pObj->IsKindOf(RUNTIME_CLASS(CMyClass));

동적 객체 생성
객체를 동적으로 생성한다.

2단계
DECLARE_DYNCREATE, IMPLEMENT_DYNCREATE
실행 시간 클래스 정보, 동적 객체 생성
사용예
CRuntimeClass
* pRuntimeClass = RUNTIME_CLASS(CMyClass);

CObject* pObject = pRuntimeClass->CreateObject();


직렬화
객체를 저장하거나 읽어들인다.

3단계
DECLARE_SERIAL, IMPLEMENT_SERIAL
실행시간 클래스 정보, 동적 객체 생성, 직렬화
사용예 

void CMyClass::Serialize (CArchive& ar){} // CObject에서 정의된 함수 재정의 필요

타당성 점검
객체 상태를 점검한다.
AssertVaild() 재정의.

집합 클래스와의 호환성
서로 다른 클래스 객체를 집합 클래스에 저장할 수 있도록 한다.
CObject 클래스 상속에 의한..

'Develop' 카테고리의 다른 글

그리기, 쓰기 등등 함수  (0) 2009.10.21
Device Context (DC)  (0) 2009.10.21
MFC 전역함수  (0) 2009.10.21
Hash Table [펌]  (0) 2009.10.21
네트워크 프로그래밍 [퍼옴]  (0) 2009.10.12

Hash Table

해시 테이블은 단순한 표현인 배열을 일반화 한것이라 할 수 있다.
일반적인 배열에 대한 직접 번지화 방법은 배열의 임의의 위치를 O(1)에 접근하는 효율적인 방법이다.
해시 테이블은 마찬가지로 직접 번지화 방법을 이용한다.
다만 차이점이 있다면 해시 테이블의 경우 키를 배열의 인덱스로 사용하지 않고 키로부터 계산한 값을 인덱스로 사용한다.

만약 서로 다른 여러 키로부터 계산된 인덱스 값이 동일할 경우 충돌이라고 하고 이를 해결하기위해 적절한 해시 함수를 작성하거나, 체이닝, open-addressing 등 을 이용한다.
여기서 적절한 해시 함수란 결국 m개의 공간에 n개의 데이터가 골고루 해시되게하는 함수를 의미한다.

체이닝
- 같은 위치에 해시되는 원소들을 리스트의 형태로 넣는 방법. 이를 통해 충돌을 처리 할 수 있다. 체이닝을 했을때의 작동 시간은 각각 얼마의 저장공간을 가지고 몇개가 저장되어있는지가 관건이다. 총 n 개의 데이터가 모두 같은 위치에 해시 될경우가 최악의 경우라 할 수 있다.
m개의 저장공간을 가지고 n개가 저장된 해시테이블의 적재율은 n/m으로 정의된다.
m개의 위치에 골고루 해시된다고 할 때 이러한 것을 단순 균등 해싱이라고 한다.

Open-addressing
open-addressing기법은 체이닝과 달리 모든 원소들이 해시 테이블에만 저장되는 특성을 가진다.따라서 적재율은 절대 1을 넘을 수 없다.
 해시 테이블에 데이터를 삽입할 경우 해시함수를 통해 데이터를 삽입하고 만약 그 공간이 다른 데이터로 채워져있을경우 키를 저장할 빈 공간을 찾을때까지 해시테이블을 연속해서 조사해나간다.
이러한 방법으로는 선형조사방법, 2차원조사 방법, 중복 해싱방법이 있다.

선형조사 방법은 h(i, i ) = (h'(k) + i ) mod m 과 같은 식을 이용하는 것으로 i를 0부터 m-1식 선형적으로 증가시키며 빈공간을 찾아간다. 구현하기 쉬우나 하나의 영향으로 여럿이 collision되는 primary clustering이 단점이다.

2차원 조사(Quadratic probing)의 경우 h(k,i) = (h'(k) + c1i + c2i^2) mod m 과 같은 식을 이용한다.

중복해싱 (Double hashing)의 경우 h(k,i) =  (h1(k) + i* h2(k))mod m 과 같은 식을 이용하여 계산한다. 

'Develop' 카테고리의 다른 글

그리기, 쓰기 등등 함수  (0) 2009.10.21
Device Context (DC)  (0) 2009.10.21
MFC 전역함수  (0) 2009.10.21
CObject 클래스의 서비스  (0) 2009.10.21
네트워크 프로그래밍 [퍼옴]  (0) 2009.10.12



1 시작

소켓 프로그램이 어렵나요? 그냥 맨페이지만 보고서는 알아내기가 좀 어럽나요? 뭔가 있어보이는 인터넷 프로그램을 만들고 싶지만 bind()를 호출하고 connect()를 호출하고 이런 저런 구조체를 뒤지고 할 시간이 없나요?

글쎄요, 제가 그 지겨운걸 다 해놓았고요, 여러분과 이 정보를 공유하고 싶군요. 바로 찾아오셨습니다. 이 문서가 바로 평균적인 C 프로그래머에게 네트워크 프로그램에 관련된 정보를 드릴겁니다.


1.1 대상

이 문서는 안내서이지 레퍼런스는 아닙니다. 아마도 소켓 프로그래밍을 처음 시작하면서 어디서부터 해야 할지 모르는 사람들에게 도움이 될겁니다. 물론 어떤 의미에서도 이 글은 소켓 프로그래밍에 관한 완벽한 안내서는 아닐 겁니다. 단지 도저히 의미를 알 수 없던 맨페이지들을 조금씩 이해하게 되기만 바랄 뿐입니다.


1.2 사용도구

대부분의 코드는 리눅스 PC에서 GNU의 gcc를 이용하여 컴파일 되었습니다. 아마도 gcc를 사용하는 어떤 플랫폼에서도 컴파일 될 것이다. 당연히 이것은 윈도우즈를 프로그래밍할때는 적용되지 않습니다. 아래의 윈도우 프로그래밍 섹션을 보십시오 (이하 존칭 생략)

1.3 공식 홈페이지

이 문서의 공식적인 위치는 chico의 캘리포니아 주립대학의 http://www.ecst.csuchico.edu/~beej/guide/net/ 이다.

1.4 Solaris/SunOS 프로그래머를 위한 유의사항

Solaris나 SunOS를 위해 컴파일 할때 몇몇의 적절한 라이브러리를 링크하기 위해 특별한 커맨드 라인 스위치를 지정할 필요가 있다. 아래처럼 "lnsl -lsocket -lresolv"를 컴파일 명령의 끝에 덧붙여라.

$cc -o server server.c -lnsl -lsocket -lresolv

만약 여전히 에러가 난다면 "-lxnet"를 커맨드 라인 끝에 덧붙일 수도 있다. 나는 그것이 정확히 무엇을 하는지는 모르지만 사람들이 그것이 필요하다고 한다.

문제가 발생하는 또다른 지점은 setsockopt()를 호출하는 부분이다. 함수 원형이 내 리눅스 박스와 다르다, 따라서

int yes=1;

대신에

char yes='1'; 을 입력하라

내가 Sun박스를 가지고 있지 않기 때문에, 위의 어떤 정보도 테스트해보지 않았다-- 이것은 사람들이 e-mail로 나에게 알려준 것들이다.

1.5 윈도우 프로그래머들을 위한 주의사항


나는 특별히 윈도우를 싫어하고 Linux나 BSD또는 Unix를 써보기를 권하지만 여전히 윈도우에서 사용하겠다는 사람들이 있었다. 첫번째로, 내가 여기서 언급한 꽤많은 헤더파일들은 무시하라. 당신이 포함해야할 것은

#include

뿐이다.

잠깐! 당신은 또한 소켓라이브러리로 어떤일을 하기 전에 WSAStartup()를 호출해야 한다. 그것을 하기 위한 코드는 다음과 같다.

#include { WSADATA wsaData; //if this doesn't work //WSAData wsaData; //then try this instead if(WSAStartup(MAKEWORD(1,1), &wsaData) != 0){ fprintf(stderr, "WSAStartup failed.\n"); exit(1); }

당신은 또한 당신의 컴파일러가 일반적으로 wsock3.lib나 winsock32.lib로 불리는 Winsock라이브러리를 링크하도록 해야한다. VC++하에서는 이것들은 Project메뉴의 Setting아래에서 Link탭을 클릭해서 "Object/library modules"를 통해 이루어 진다. "wsock32.lib"를 그 리스트에 덧붙여라. 라고 들었다.

마지막으로 당신은 WSAClenaup()를 소켓라이브러리를 다 쓴후에 호출해야 한다. 자세한 것은 온라인 도움말을 보라.

일단 그것을 하면 이 안내서의 나머지 예제는 몇몇 예외를 제외하고 일반적으로 적용될것이다. 하나 예를 들면, 당신은 close()를 소켓을 닫기위해 사용할수 없고 closesocket()를 대신 사용해야 한다. 또한 select()는 파일기술자(stdin의 0같은)가 아니고 소켓 기술자에만 사용할 수 있다.

당신이 사용할 수 있는 소켓 클래스인 CSocket도 있다. 더 많은 정보는 당신의 컴파일러의 도움말페이지를 참고하라.

Winsock에 대한 더 많은 정보를 얻기위해서는 Winsock FAQ를 읽고 거기서 시작하라.

마지막으로 나는 윈도우즈가 fork() 시스템 호출이 없다고 들었는데 그것은 나의 몇몇 예제에서 쓰이고 있다. 아마도 POSIX라이브러리나 그것이 작동하게하기 위한 어떤것을 링크하거나 매개변수가 없는 fork()대신 48억개의 매개변수를 가지는 CreateProcess()를 사용할 수도 있다. 만약 당신이 그렇게까지 하기 싫다면 CreateThread()는 좀 더 요약하기 쉽다. 불행하게도 멀티스레딩은 이 문서의 범위에서 벗어난다. 내가 이야기 할 수 있는것은 여기까지다.

1.6 이메일 정책


나는 이메일 질문에 답할수 있는 여유가 있으니 편하게 메일을 보내도 되지만 답장을 보낸다고 확신할 수는 없다. 나는 꽤 바쁘게 살고 있어서 당신이 보낸 질문에 답할 수 없을때도 있다. 그럴 경우에는 나는 보통은 메시지를 지운다. 개인적인 감정은 없다; 당신이 요구한 자세한 답변을 할 수 없을 뿐이다.

대개 질문이 복잡할 수록 답변이 없을 확률이 높다. 만약 메일 보내기 전에 당신의 질문을 좁은 범위로 한정해 주고 어떤 적절한 정보( 플랫폼, 컴파일러, 당신이 받은 에러 메시지, 그리고 당신이 생각하기에 오류를 잡기에 적당하다고 생각되는 어떤것)를 포함한다면 답변을 확률은 더 높아진다. 더 많은 질문법은 ESR의 문서, [http]How To Ask Questions The Smart Way를 읽어보라.

만약 당신이 답변을 얻지 못했다면 좀 더 찾아보고 답을 찾기위해 노력해보고 그래도 안된다면 당신이 발견한 정보와 내가 줄 수 있는 충분한 정보를 포함한 메일을 보내라.

나는 당신을 어떻게 메일을 쓰고 안써야 하는지에 대해 잔소리를 했다. 나는 정말로 몇년간 내가 이 안내서에대해 받은 칭찬에 대해 감사하고 싶다. 그것은 정말 사기를 끌어올린다.그리고 그것이 쓸모있다는 말을 듣는것은 나를 정말 기쁘게 한다. ;-) 고맙다!

1.7 미러링

공적으로든 사적으로든 미러해 준다면 정말 고맙겠다. 만약 공식적으로 이 사이트를 미러링하고 내가 메인페이지에서 링크하기를 원한다면 나에게 beej@piratehaven.org로 메일을 보내면 된다.


1.8 번역자에게

만약 당신이 이 글을 번역하기를 원한다면 beej@piratehaven.org로 메일 보내달라. 그러면 나는 메인페이지에서 당신이 번역한 글을 링크할 것이다.

번역물에 당신의 이름과 이메일 주소를 추가하는것은 자유다. 미안하지만 공간의 제약때문에 번역물을 내 스스로 제공할 수는 없다.

1.9 저작권과 배포권


Beej's Guide to Network Programming는 ⓒ 1995-2001 Brian "Beej"Hall에게 저작권이 있다.

이 안내서는 내용물이 변형되지 않고, 완전하게 제공되며, 저작권 정보가 남아있는한 어떠한 매체로도 재출력될 수 있다.

특히교육자들에게 이 안내서를 그들의 학생들에게 추천하거나 복사본을 제공하기를 권한다.

이 안내서는 번역이 정확하고 모든 문서가 재출력된다면 자유롭게 어떤 언어로도 번역될 수 있다. 번역은 번역자의 이름과 접근 정보가 포함 될 수도 있다.

이 문서에 포함된 C 소스코드는 공공의 사용을 허가한다. 더 많은 정보는 beej@piratehaven.org에게 문의하라.



2 소켓이란 무엇인가.

소켓이란 단어는 많이 들었을 것이다. 그리고 아마도 그 소켓이 정확히 무엇인가에 대하여 궁금해 하기도 했을 것이다. 소켓은 정규 유닉스 파일 기술자를 이용하여 다른 프로그램과 정보를 교환하는 방법을 의미한다.

뭐라고라?

좋다. 아마도 유닉스를 잘하는 사람들이 이렇게 얘기하는 것을 들어본 적이 있을 것이다. "유닉스에서는 모든게 파일로 되어있군!" 실제로 그들이 얘기하는 것은 모든 유닉스 프로그램들이 어떤 종류의 입출력을 하더라도 파일 기술자를 통해서 하게 된다는 것이다. 파일 기술자는 사실 열려진 파일을 의미하는 정수일 뿐이다. 그러나 그 파일은 네트워크가 될수도 있고 FIFO, 파이프, 터미널, 실제 디스크상의 파일이 될수도 있으며 그 밖의 무엇도 다 된다는 것이다. 유닉스의 모든것은 파일이다! 따라서 당신이 인터넷을 통하여 멀리 떨어진 다른 프로그램과 정보를 교환하기 위해서는 파일 기술자를 이용하면 된다는 것이다. 믿으쇼~

"똑똑이 양반, 그 파일 기술자는 도대체 어떻게 만드는거요?" 라는게 당신의 맘속에 지금 막 떠오른 질문일 것이다. 여기에 대답이 있다. socket()을 호출하면 소켓 기술자를 얻게 되고 send(), recv()등의 소켓에 관련된 함수를 호출하여 정보를 교환할 수 있다. (man send, man recv를 해봐도 됨)

"잠깐!" 이렇게 이의를 제기하겠지. "그 소켓 기술자가 파일 기술자라면 도대체 왜 read(),write()를 쓰면 안되는거요?" 짧게 말하면 맞다. 그러나 send(),recv()를 쓰는 것이 여러모로 네트워크를 통한 정보전달을 제어하기에 도움이 된다는 것이다.

다음은 뭔가? 소켓의 종류는? DARPA 인터넷 주소(인터넷 소켓), 경로명과 지역노드(유닉스 소켓), CCITT X.25 주소(X.25 소켓, 그냥 무시해도 됨)등이 있고 아마도 당신이 쓰는 유닉스에 따라서 더 많은 종류의 소켓들이 있을 것이다. 이 문서는 첫번째 (인터넷 소켓) 하나만 설명할 것이다.




2.1 두가지 종류의 소켓

인터넷 소켓에 두가지 종류가 있나? 그렇다. 음..사실은 거짓말이다. 좀 더있긴 하지만 겁을 주고 싶지 않기 때문에 이것 두가지만 이야기 하는 것이다. RAW 소켓이라는 매우 강력한 것도 있으며 한번 봐두는 것도 좋다.

두가지 종류는 무엇인가? 하나는 스트림소켓 이고 다른 하나는 데이터그램 소켓이다. 이후에는 SOCK_STREAM, SOCK_DGRAM으로 지칭될 것이다. 데이터그램 소켓은 비연결 소켓이라고도 한다. (비록 그 소켓에서도 원한다면 connect()를 사용할 수도 있다. connect()절을 참조할것)

스트림 소켓은 양측을 신뢰성있게 연결해 주는 소켓이다. 만약 두가지 아이템을 이 소켓을 통하여 보낸다면 그 순서는 정확히 유지될 것이다. 에러까지 교정된다. 만일 에러가 생긴다면 당신 실수이고 당신실수를 막는 방법은 여기서 설명하지 않을 것이다.

스트림 소켓은 어디에 쓰이는가? 아마도 텔넷이라고 들어봤을 것이다. 들어봤느뇨? 그게 이 소켓을 쓴다. 입력한 모든 글자는 그 순서대로 전달이 되야 하는 경우이다. 사실 WWW사이트의 포트 80에 텔넷으로 접속하여 "GET pagename" 을 입력하면 HTML 화일의 내용이 우르르 나올 것이다.

어떻게 스트림 소켓이 이정도의 정확한 전송 품질을 갖추게 되는가? 이 소켓은 TCP를 이용하기 때문이다. (Transmission Control Protocol, RFC-793에 무척 자세하게 나와있다.) 아마도 TCP 보다는 TCP/IP를 더 많이 들어봤을 것이다. 앞부분은 바로 이 TCP이고 뒷부분의 IP는 인터넷 라우팅을 담당하는 프로토콜이다.

괜찮군~ 데이터그램 소켓은 어떤가? 왜 비연결이라고 하는지? 내용에 무슨 관련이 있는지? 왜 신뢰도가 떨어지지? 사실 이 소켓의 경우 당신이 데이터그램을 보낸다면 정확히 도착할 수도 있다. 또는 패킷들의 순서가 바뀌어서 도착할 수도 있다. 그러나 만약 도착한다면 그 내용은 사실 정확한 것이다.

데이터그램 소켓 또한 라우팅에는 IP를 이용하지만 TCP는 이용하지 않는다. 사실은 UDP(RFC-768)을 이용한다.

연결을 안하는가? 스트림 소켓에서처럼 열려있는 연결을 관리할 필요가 없는 것이다. 그냥 데이터 패킷을 만들어서 목적지에 관련된 IP헤더를 붙여서 발송하기만 하면 되는 것이다. 연결이 필요없다. 보통 tftp나 bootp 에 사용되는 것이다.

좋아! 그러면 데이터 패킷이 도착하지 않을지도 모르는 이런 걸 어떻게 실제 프로그램에서 사용하지? 사실 프로그램들은 UDP위에 그 나름대로의 대책을 갖추고 있는 것이다. 예를 들면 tftp같은 경우에는 하나의 패킷을 보낸 후에 상대편이 잘 받았다는 응답 패킷이 올때까지 기다리는 것이다. 만약 일정시간(예를 들면 5초)동안 응답이 없으면 못받은 것으로 간주하고 다시 보내고, 다시 보내고 응답이 있으면 다음 패킷을 보내고 하게 되는것이다. 이 잘받았다는 응답(ACK reply) 방식은 사실 SOCK_DGRAM을 사용할 경우 매우 중요하다.




2.2 네트워크 이론과 저 아래의 알 수 없는 것들

간단히 프로토콜의 레이어에 대해서 언급을 했지만(UDP위에 나름대로의 대책 어쩌구) 이제는 실제로 네트워크가 어떻게 작동하는 지를 알아볼 때가 되었고 실제로 SOCK_DGRAM이 어떻게 구성되는 지를 알아볼 필요가 있을 것같다. 사실 이 절은 그냥 넘어가도 된다.

여러분~ 이제는 데이타 캡슐화에 대하여 배우겠어요~ 사실 이것은 매우 중요하다. 얼마나 중요하냐면 우리 학교에서 네트워크 코스를 통과하려면 반드시 알아야 하는 사항이기 때문이다. (흠..) 내용은 이렇다. 데이터 패킷이 만들어지면 먼저 첫번째 프로토콜(tftp 프로토콜)에 필요한 머리말과 꼬리말이 붙는다. 이렇게 한번 캡슐화된 내용은 다시 두번째 프로토콜(UDP)에 관련된 머리말과 꼬리말이 다시 붙게 된다. 그 다음에는 IP, 그 다음에는 마지막으로 하드웨어 적인 계층으로서 이더넷 프로토콜로 캡슐화가 되는 것이다.


다른 컴퓨터에서 이 패킷을 받게 되면 하드웨어가 이더넷 헤더를 풀고 커널에서 IP와 UDP 헤더를 풀고 tftp 프로그램에서 tftp헤더를 풀고 하여 끝으로 원래의 데이터를 얻게 되는 것이다.

이제 드디어 악명높은 계층적 네트워크 모델(Layered Network Model)을 얘기할 때가 된것 같다. 이 모델은 다른 모델들에 비해서 네트워크의 시스템을 기술하는 측면에서 많은 이점이 있다. 예를 들면 소켓 프로그래밍을 하는 경우 더 낮은 계층에서 어떤 물리적인 방식(시리얼인지 thin ethernet인지 또는 AUI방식인지)으로 전달되는 지에 대하여 전혀 신경을 쓰지 않고도 작업이 가능해 질 수 있다는 것이다. 실제 네트워크 장비나 토폴로지는 소켓 프로그래머에게는 전혀 관계없는 분야이다.

더이상 떠들지 않고 다음 계층들을 일러 주는데 만일 네트워크 코스에서 시험을 보게 될 경우라면 외우는 것이 좋을 것이다.

Application Presentation Session Transport Network Data Link Physical

물리적 계층(Physical layer)는 하드웨어(시리얼, 이더넷등) 이다. 어플리케이션 계층은 상상할 수 있듯이 물리적 계층의 반대편 끝이다. 이 계층을 통하여 사용자는 네트워크와 접촉하게 되는 것이다.

사실 이 모델은 자동차 수리 설명서 처럼 실질적인 뭔가를 할 수 있기에는 너무나 일반적인 얘기이다. 유닉스의 경우를 들어 보다 실질적인 얘기를 해 본다면,

Application Layer (telnet, ftp, etc.) Host-to-Host Transport Layer (TCP, UDP) Internet Layer (IP and routing) Network Access Layer (was Network, Data Link, and Physical)

이러한 계층으로 살펴 본다면 아까의 데이터 캡슐화가 각각 어떤 계층에 속하는 가를 알 수 있을 것이다.

이렇게 많은 작업이 하나의 데이터 패킷을 만드는데 동원되는 것이다. 이 내용을 당신이 데이터의 패킷 머리 부분에 몽땅 타이핑 해 넣어야 한다는 얘기다. (물론 농담이다.) 스트림 소켓의 경우 데이터를 내보내기 위해 해야 할 일은 오직 send()를 호출하는 것 뿐이다. 데이터 그램의 경우에는 원하는 방식으로 데이터를 한번 캡슐화하고 (tftp방식등) sendto()로 보내버리면 되는 것이다.커널이 전송계층과 인터넷 계층에 관련된 캡슐화를 하고 나머지는 하드웨어가 한다. 아~ 첨단 기술!!

이것으로 간단한 네트워크 이론은 끝이다. 참, 라우팅에 관해서 하고 싶던 얘기들을 하나도 안했다. 흠, 하나도 없다. 정말이지 라우팅에 관해서 하나도 얘기하지 않을 것이다. 라우터가 IP헤더를 벗겨내서 라우팅 테이블을 참조하여 어쩌구 저쩌구...만일 정말로 여기에 관심이 있다면 IP RFC를 참조할 것이며 만약 거기에 대해서 하나도 알지 못한다면! 생명에 지장은 없다.




3 구조체들과 데이타 처리

결국은 여기까지 왔군. 드디어 프로그래밍에 관한 얘기를 할 때이다. 이 절에서는 실제로 꽤나 이해하기 어려운 소켓 인터페이스에서 쓰이는 여러가지 데이터 타입에 대한 얘기를 할 예정이다.

먼저 쉬운것. 소켓 기술자이다.소켓 기술자의 데이터 형은
int

이다. 그냥 보통 int이다. (정수형)

뭔가 좀 이상하더라도 그냥 참고 읽기 바란다. 이것은 알아야 한다. 정수에는 두 바이트가 있는데 상위 바이트가 앞에 있거나 또는 하위 바이트가 앞에 있게 된다. 앞의 경우가 네트워크 바이트 순서이다. 어떤 호스트는 내부적으로 네트워크 바이트 순서로 정수를 저장하는 경우도 있으나 안그런 경우가 많다. 만일 NBO라고 언급된 정수가 있다면 함수를 이용하여 (htons()함수) 호스트 바이트 순서로 바꾸어야 한다. 만약 그런 언급이 없다면 그냥 내버려 둬도 된다.

첫번째 구조체, struct sockaddr. 이 구조체는 여러가지 형태의 소켓 주소를 담게된다.
struct sockaddr { unsigned short sa_family; /* address family, AF_xxx */ char sa_data[14]; /* 14 bytes of protocol address */ };

sa_family 는 여러가지가 될 수 있는데, 이 문서에서는 그중에서 "AF_INET"인 경우만 다루게 된다. sa_data 는 목적지의 주소와 포트번호를 가지게 된다. 약간 비실용적이군.

sockaddr 구조체를 다루기 위해서는 다음과 같은 parallel structure를 만들어야 한다. ("in"은 인터넷을 의미한다.)
struct sockaddr_in { short int sin_family; /* Address family */ unsigned short int sin_port; /* Port number */ struct in_addr sin_addr; /* Internet address */ unsigned char sin_zero[8]; /* Same size as struct sockaddr */ };

이 구조체는 각각의 항을 참조하기가 좀더 쉬운 것 같다. 주의할 점은 sin_zero배열은 sockaddr 과 구조체의 크기를 맞추기 위해서 넣어진 것이므로 bzero()나 memset()함수를 이용하여 모두 0으로 채워져야 한다. 또한 꽤 중요한 점인데, 이 구조체는 sockaddr 의 포인터를 이용하여 참조될 수 있고 그 반대도 가능하다는 것이다. 따라서 socket()함수가 struct sockaddr * 를 원하더라도 struct sockaddr_in을 사용할 수 있고 바로 참조할 수도 있는 것이다. 또한 sin_family는 sa_family에 대응되는 것이며 물론 "AF_INET"로 지정되어야 하며 sin_port, sin_addr은 네트워크 바이트 순서로 되어야 하는 점이 중요한 것이다.

그러나! 어떻게 struct in_addr sin_addr 전체가 NBO가 될 수 있는가? 이 질문은 살아남은 가장 뭣같은 유니온인 struct in_addr 에 대한 보다 신중한 검토가 필요할 것같다.
/* Internet address (a structure for historical reasons) */ struct in_addr { unsigned long s_addr; };

음.. 이것은 유니온 "이었었"다. 그러나 그런 시절은 지나갔다. 시원하게 없어졌군! 따라서 만약 "ina"를 struct sockaddr_in형으로 정의해 놓았다면 ina.sin_addr.s_addr 로 NBO 상태의 4바이트 인터넷 어드레스를 정확하게 참조할 수 있을 것이다. 만약 사용하는 시스템이 struct in_addr에 그 끔찍한 유니온을 아직도 사용하고 있더라도 #defines S 덕분에 위에 한것과 마찬가지로 정확하게 참조할 수는 있을 것이다.




3.1 순서 바꾸기

이제 다음 절로 왔다. 네트워크와 호스트 바이트 순서에 대해서 말이 너무 많았고 이제는 실제 움직일 때라고 본다.

좋다. 두가지 형태의 변환이 있는데 하나는 short(2 바이트)와 long(4바이트)의 경우이다. 이 함수들은 unsigned변수에서도 잘 작동된다. 이제 short변수를 호스트 바이트 순서에서 네트워크 바이트 순서로 변환하는 경우를 보자. 호스트의 h 로 시작해서 to 를 넣고 네트워크의 n 을 넣은 후 short의 s 를 넣는다. 그래서 htons()이다. (읽기는 호스트 투 네트워크 쇼트이다.)

너무 쉬운가?

사실 h,n,s,l 의 어떤 조합도 사용가능하다. (물론 너무 바보스러운 조합을 하지는 않겠지..예를 들어 stolh, 쇼트 투 롱 호스트?? 이런건 없다. 적어도 이 동네에서는없다.) 있는 것들은 다음과 같다.

|| htons()--"Host to Network Short" htonl()--"Host to Network Long" ntohs()--"Network to Host Short" ntohl()--"Network to Host Long" ||

아마도 이제 상당히 많이 알게된 것같이 생각들을 할 것이다. "char의 바이트 순서를 어떻게 바꾸지?(역자주: 이 질문은 아마 의미없는 질문으로 한 것 같은데 답도 없고 더이상의 언급이 없는 것으로 보아 빼고 싶은 부분이다.)" 또는 "염려마, 내가 쓰는 68000 기계는 이미 네트워크 바이트 순서로 정수를 저장하니까 변환할 필요는 없어 " 라고 생각할 수도 있을 것이다. 그러나 꼭 그렇지만은 않다. 그렇게 작성된 프로그램을 다른 기계에서 작동시킨다면 당연히 문제가 발생할 것이다. 여기는 유닉스 세계고 이기종간의 호환성은 매우 중요한 것이다. 반드시 네트워크에 데이터를 보내기 전에 네트워크 바이트 순서로 바꿔서 보낸다는 것을 기억할 지어다.

끝으로 sin_addr, sin_port는 네트워크 바이트 순서로 기록하는데 왜 sin_family는 안 그러는가? 답은 간단하다. sin_addr과 sin_port는 캡슐화되어 네트워크로 전송되어야 하는 변수인 것이다. 따라서 당연히 NBO여야 한다. 그러나 sin_family는 시스템 내부에서 커널에 의해서만 사용되는 변수이며 네트워크로 전송되지 않는 것이므로 호스트 바이트 순서로 기록되어야 하는 것이다.




3.2 IP주소는 무엇이며 어떻게 다루는가?

다행스럽게도 IP주소를 산정해 주는 수많은 함수들이 있으며 따라서 4바이트의 long변수에 직접 계산해서 << 연산자를 이용해서 집어넣어야 하는 수고는 할 필요가 없다.

먼저 struct sockaddr_IN ina가 정의되어 있고 132.241.5.10 이 IP 주소이며 이 값을 변수에 넣어야 한다고 가정해 보자. inet_addr()함수가 바로 이럴때 사용하는 것이다. 그 함수는 숫자와 점으로 구성된 IP주소를 unsigned long 변수에 집어 넣어 준다. 다음과 같이 하면 된다.
ina.sin_addr.s_addr = inet_addr("132.241.5.10")
inet_addr()는 결과값으로 이미 NBO인 값을 돌려주며 굳이 htonl()을 또 사용할 필요는 없다는 점에 주의해야 한다. 멋지군!

그러나 위의 짤막한 코드는 그렇게 견실해 보이진 않는다. 왜냐하면 inet_addr()은 에러의 경우 -1을 돌려주게 되며 unsigned long에서 -1은 255.255.255.255를 의미한다. 이는 인터넷 브로드캐스트 어드레스가 된다. 나쁜 녀석. 항상 에러 처리를 확실히 하는것이 좋다.

좋다. 이제 IP주소를 long에 넣는것은 알았는데 그 반대는 어떻게 할 것인가? 만약에 값이 들어있는 struct in_addr은 가지고 있는데 이를 숫자와 점으로 표시하려면? 이 경우는 inet_ntoa()를 쓰면 된다.(ntoa 는 네트워크 투 아스키이다.)
printf("%s",inet_ntoa(ina.sin_addr));

위의 코드는 IP주소를 프린트 해 줄것이다. 이 함수는 long 변수가 아니라 struct in_addr 를 변수로 받아 들인다는 점을 주의해야 한다. 또한 이 함수는 char 에 대한 포인터를 결과로 돌려 주는데 이는 함수내에 static 한 공간에 저장되며 따라서 매번 함수가 호출될 때마다 이 포인터가 가리키는 곳의 값은 변화한다는 것이다. 즉 예를 들면,
char *a1, *a2; . . a1 = inet_ntoa(ina1.sin_addr); /* this is 198.92.129.1 */ a2 = inet_ntoa(ina2.sin_addr); /* this is 132.241.5.10 */ printf("address 1: %s\n",a1); printf("address 2: %s\n",a2);
의 출력은 이렇게 나올 것이다. address 1: 132.241.5.10 address 2: 132.241.5.10

만약에 이 값을 저장해야 할 필요가 있다면 strcpy()를 이용하여 고유의 char 배열에 저장해야 할 것이다.

이절에서 얘기할 것은 다 했다. 나중에 "whitehouse.gov" 문자열을 해당하는 IP주소로 

'Develop' 카테고리의 다른 글

그리기, 쓰기 등등 함수  (0) 2009.10.21
Device Context (DC)  (0) 2009.10.21
MFC 전역함수  (0) 2009.10.21
CObject 클래스의 서비스  (0) 2009.10.21
Hash Table [펌]  (0) 2009.10.21

공짜로 가게된 KGC2009.
2005년 이후 처음이다.

코엑스 북문.. 한참 찾았다 --

7일 아침 KEYNOTE는
CRYTEK의 Cevat Yerli님의 그래픽 어쩌구,
XLGAMES의 송재경님의 MMORPG 변화하는 세계
였다.

외국인 아저씨가 너무 오랫동안 강연하는 바람에 두번째 KEYNOTE가 짧았다.

송재경님의 강연 내용은 과거와 현재의 MMORPG를 정의하고 미래의 MMORPG의 방향에 대한 강연이었다.
1세대는 리니지, 울티마온라인
으로 대표된다.
자유분방한 가상세계이다.
하지만 자유로운만큼 문제점도 많았다.
길막기, 사냥터독점, 매점매석, PK, 등등등

2세대는 WOW, AION으로 대표된다.
1세대의 문제점들을 고치는 과정에서 테마파크가 됐고, 자유도의 제한이 생겼다.
2세대는 수동적인 소비로써 개발사에서 제공한 콘텐츠를 소비하는거에 불과했다.
그리고 고정적인 세계이다. 사용자는 게임에 마련된 것들은 단순히 이용할 뿐이다.
게임 세계에 변화를 주지는 못한다.
또한 사용자간의 상호작용은 제한적이 되었다.
PK는 막았지만 넓은 의미에서의 상호작용은 제한되었다.
2세대에서는 게임의 본질인 재미는 인스턴스던전에서 얻었고
필드는 단순히 커다란 로비일 뿐이다.
송재경님은 이걸 연출된 즐거움이라고 표현하셨다.

앞으로의 MMORPG는?
다시 자유도가 높은 가상세계로의 회귀다.
3가지 측면을 예로 들었다.
변화하는 환경
계절, 기후, 밤낮, 조수간만, 천체등의 시간적인 환경들(지금 구현되있는 게임도 많다)
땅파기, 나무심기, 집짓기, 성짓기등의 지형적인 환경들
이 있다.
사용자에 의해 지형에 변화가 생기면 앞으로도 쭉 그 세계에서 그 영향은 유지가 된다.
(비가 와서 물도 고이고 풍화작용으로 산도 깎일까?)
관계
고용, 연애, 정치, 외교등의 NPC와의 관계(고용은 그라나도에스파다에 있는거 같은데?)
협력은 가족, 마을, 국가, 제작, 건설, 경쟁은 직접, 간접적인 PC와의 관계
UCC
사용자가 제작한 리소스, 퀘스트, 던전 등
이것들을 창발적인 즐거움이라 하셨다.

음.. 나도 이런걸 한번쯤은 고민해봤지.
썸머워즈에 나오는 OZ정도면 비슷할까?

이런것들을 하려면 서버가 참 힘들어 지겠구나 하는 생각도 했다.
좋은 강연이였다.

다음에 들은 강연은
Kiyoshi Shin님의 How technology innovation makes new game trend~seeing new feature game for next 10 years 이다. (제목 무진장 길다)
앞으로의 게임 트랜드에 대한 강연이었다.

지금 현재 개발되고 있는 게임들은 개발비용이 말도 못하게 크다는 것,
하지만 그 개발비도 회수하지 못해 망하는 회사가 많다는 것.

일본에서는 휴대전화로 하는 트위터와 무료게임이 차지하는 비율이 점점 늘고 있다.

스케일이 큰 게임은 주로 남성들이 하고,
스케일이 작고 가벼운 무료게임은 여성들이 많이 한다.

따라서 스케일이 크고 무거운 게임보다는 작고 가벼운 게임이 차라리 낫다.

미국에는 선데이개발자(취미개발자)가 많다.
애플의 아이폰, 아이팟터치로 인해(앱스토어) 유통과 개발의 일반화를 이루었고,
소프트웨어의 저가화 경쟁을 일으키고 있다.
(강연 처음부터 끝까지 애플을 무지 X다. 앱스토어의 소프트웨어 중 90%는 쓰레기라며..)

이 강연을 들으면서 생각한점.
플랫폼 제작사가 소프트웨어 제작사가 되어야 한다. (그 반대라도)
애플은 획기적이지만 실패못한 프로젝트들을 기가막힌 방법으로 자신의 것으로 만들어 성공시킨다.
사실 앞으로 모바일에서 많은 일들을 할것이다. 게임마져.
물론 모바일은 베터리와 하드웨어, 데이터전송료로 인해 제한이 있지만,
언젠간 극복되지 않을까?
갈수록 게임의 크기가 작아지고 이용료가 무료로 전환된다면, 난 뭘 먹고 살지!?

3번째 강연은 김현우님의 멀티 코어를 이용한 병렬처리 게임엔진과 Nebula3였다.
그냥 Nebula 광고 같았다는..(오픈소스니까 공부하면 많은걸 얻 을수 있겠지)

4번째 강연은 최흥배님의 Visual C++ 10
뭔가 얻는다기보단 궁금한것들이 많이 생긴 강연
C++ 0x,
Static_assert()랑 assert()가 뭐가 다른지..
lambda,
http://vsts2010.tistory.com/   <==   공식 블로그.

좀 아쉬운게 많은 하루였다.
마지막날 KEYNOTE 들어야지!

'Think' 카테고리의 다른 글

칭찬의 역효과  (0) 2011.04.09
SBS스폐셜 '온난화의 마지막 페이지'  (0) 2009.10.26

+ Recent posts