본의 아니게 업계에 알려진 Rhea君의 건강은 지금은 꽤나 좋아졌습니다.
각종 디스크 상담이 쇄도하고 있습니다.
그러나 아직 아래 사진과 같은 선물을 줄 여자친구를 만들지 못했으므로 조금은 더 쉬어야합니다.
진정한 남자로 선택을 받는 시간이 한달도 채 남지 않았습니다.

진정한 남자로 선택을 받는 시간이 한달도 채 남지 않았습니다.

많은 게임 업체분들이 백수인 저를 위해 사심없고 우정 어린, 밥과 술을 사주셨는데,
현재 삼성동 사옥 돋는 N모사만 밥과 술과 향응을 제공하지 않았습니다.
여전히 성장기라 배가 고픕니다. 참고로 저는 소고기보다 물고기류를 더 좋아합니다(삼성동 오징어세상에서 오징어 통찜이나.).
그리고 백수를 갈취한 선릉역 N모사와 오리역 N모사 직원느님을 고발합니다(...뻥).

1. 네트워크 아키텍쳐
익히 알려져 있는대로, 소켓 속에는 주요 함수가 몇개 없습니다.
클라이언트를 기준으로 하면 연결을 위한 connect(), 주고받는 send()/recv(), 연결해제를 위한 close()뿐입니다.
그러나 많은 게임들은 이 몇안되는 단순한 함수들로 클라이언트/서버(이하 C/S)과 Peer-To-Peer(이하 P2P)를 오가는
마법과 같은 네트워크들을 보여줍니다.

1.1 모든 것은 서버로 C/S
C/S 모델은 100% 서버 지향 네트워크 아키텍쳐입니다.
사용자는 게임 클라이언트 실행시 서버에 의해 게임 플레이가 결정됩니다.

가장 좋은 예는 MMORPG와 맞고/포커같은 카드류 게임입니다.
C/S 모델은 MMORPG가 발전한 우리 나라에서 크게 발전된 모델입니다(기술뿐만 아니라 운영도 포함해서).

C/S 모델의 장점은 보안에 강력하다는 점입니다.
모든 결정이 서버에 의해 판가름나므로 해킹에 강합니다.
만약 해킹을 통해 어떤 짓을 했다고 하더라도 다음날 아침이면 들통납니다.
대부분의 온라인 게임 회사들일 경우, 출근하자마자 볼수 있는 것이 어제 급격히 레벨이 오른 유저의 전적입니다.
당장 제재가 가해지지는 않지만 어김없이 들키고 맙니다.
...나머지는 서버개발자가 아닌, 이름은 친절하지만 사실은 무서운 아저씨들인 고객만족팀에서 해결해주시곘죠.

여기서 한가지 명확하게 짚고 넘어갈 것이 있습니다.

우선 "클라이언트/호스트"와 "클라이언트/서버"의 개념입니다.
우선 우리가 익숙한 PC통신이나 UNIX를 생각해봅시다.
PC통신화면이나 텔넷으로 접속한 UNIX 화면은 100% 서버에서 던져주는 TEXT정보입니다.
이 당시에는 "서버"라는 용어 대신 "호스트(host)"라는 용어를 썼으며 이때는 반드시 로그인(Log in)이라는 용어를 썼습니다.

이 의미는 클라이언트에는 0.1%의 할일도 없으며 모든 것을 서버에서 전해주는 것을 받아 그 안에서 작업한다는 것입니다.
돌이켜보면 PC통신에 사용된 프로그램을 가르켜 단말기 예뮬레이터(Terminal Emulator)라고 불렀습니다.
PC가 아닙니다. 단말기라는 것은 PC가 아니라 Host에 접속해서 Host가 보내주는 화면과 텍스트 기반의 요청을 보내는 것 뿐입니다.

따라서 클라이언트는 Host 속으로 들어간다는 의미에서 로그인(Log in)이라 불렀습니다.

저승 로긴하시는 마미성님

저승 로긴하시는 마미성님


그리고 단말기는 사라지고 PC가 흔해진 시대에 들어서며 클라이언트/서버의 시대가 왔습니다.
클라이언트/서버의 의미는 클라이언트와 서버가 "평등"하다는 의미이며 하나의 작업을 처리하기 위해
클라이언트 컴퓨터와 서버 컴퓨터가 협력해서 작업을 한다는 의미입니다.

그래서 로그온(Log on)이라 부릅니다.

윈도우 역시 Log on/Log off 라는 표현을 씁니다.
이는 커널이라는 서버와 애플리케이션이라는 클라이언트가 협업한다는 의미입니다.
오래전 윈도우95가 등장할때, "본격 32비트 클라이언트/서버 OS"라고 했는데
일부 사람들은 윈도우95에 소켓이 내장되어 그렇게 부른다고 했지만 그게 아니라 커널과 애플리케이션이 통신한다는 의미입니다.

네트워크에서 클라이언트/서버 역시 마찬가지입니다.
웹페이지를 볼까요?
흔히보는 홈페이지 가입할때, 특정 항목을 제대로 적지 않았으면 다시 적으라고 알려줍니다.
이는 서버에서 검사할 수도 있고, 클라이언트에서 자바스크립트로 검사할 수도 있습니다.
어느 쪽이든 가능합니다.

하지만 서버 측에서 검사할려면 일단 데이터를 서버로 넘겨야 합니다.
트래픽 측면을 본다면 자바스크립트로 처리하는게 효율성에서 맞습니다.
그런데 또 문제가 있습니다.

비쥬얼 스튜디오같은 자바스크립트 디버깅 툴만 있으면 자바스크립트에서 처리하는 양식 검사 따위는 아주 쉽게 무시해 버릴수 있습니다!
이렇게 되면 효율성을 무시하고 서버에서 검사를 해야 합니다.
도대체 뭐가 맞는 것일까요?

홈페이지 이야기를 하니 헛갈린다면 게임으로 넘어옵시다.
C/S기반의 슈팅 게임을 있다고 할때 공격 성공 판정을 서버에서 해야할까요, 클라이언트에서 해야 할까요?
서버에서 하자니 매 키입력마다 네트워크를 타야 합니다.
클라이언트에서 하자니 검증이 불가능합니다.

정답은 그때그때 다르다이고 서버에서 처리할 것과 클라이언트에서 처리할 것을 알맞게 나눠야 한다는 것입니다.
앞으로 게임을 만들며 이 문제를 실전에서 다시 짚을 것입니다.

1.2 우리끼리 놀자 P2P
P2P는 유저들끼리 데이터를 주고 받으며 게임을 진행하는 방식입니다. P2P의 대표적인 게임이라면 스타크래프트와 FPS게임들일 것입니다.
그러나 MMORPG 위주의 우리 나라에서는 꽤나 오랜 시간 P2P 기술이 홀대를 받았습니다.
보안에 취약하고 지금처럼 FPS가 유행하기 전까지는 P2P에 어울리는 게임이 없었기 때문입니다.

P2P의 장점은 로비를 제외하면 대용량 서버를 구축할 일이 없다는 것입니다.
단점은 클라이언트가 결국 서버와 클라이언트, 모두를 맡아야 하므로 네트워크 측면에서 만들기가 좀더 어렵다는 점입니다.
특히 P2P는 (플레이어수-1)((플레이어수-1)-1) /2 만큼 연결을 가져야 하므로 사용자가 늘어날때마다 디버깅이 힘들어집니다.
그리고 절대 잊을수 없는 문제가 있지요, 바로 NAT(Network Address Translator)이라고 불리는 공유기 문제입니다.
공유기 아래에 있는 Peer는 서버로 작동할 수 없습니다. 그래서 홀펀칭(hole punching)이라는 방법이 거론됩니다.

그러나 현실적으로 P2P만으로 게임 서비스를 만들기는 불가능합니다.
친구들을 모으고 채팅을 하며 어떤 방이 있는지 목록을 보기 위해서는 반드시 중앙에 서버가 있어야 합니다.
스타크래프트로 치면 바로 배틀넷(battle.net)이죠.

구분 장단점 주 프로토콜 게임 스타일
C/S 장점 : 보안에 유리
단점 : 높은 트래픽, 대용량 서버 기술 필요
TCP가 주로 사용되나 UDP도 사용 온라인 게임
P2P 장점 : 대용량서버 필요없음
단점 : 복잡성 증가, NAT 홀펀칭 필요
서버연결은 TCP,
P2P에는 UDP가 주로 사용
네트워크 게임
<표1. C/S와 P2P 정리>

온라인 게임과 네트워크게임의 차이도 이번에 짚고 넘어가죠.
온라인 게임은 사용자의 대부분의 MMORPG처럼 접속이 없어도 서버 시간이 흐르는 게임을 의미합니다. 내가 서버에 접속하지 않아도 서버는 이벤트가 진행되고 밤낮이 바뀝니다. 네트워크 게임은 방을 만들어 진행하는 단판승부 위주의 게임을 의미합니다. 스타크래프트, 맞고 같은 게임이 대표적이죠.
이 강좌의 제목은 아무 생각없이 네트워크 게임 튜터리얼이라 지었는데, 어떤 예제가 나오더라도 그냥 무시해주시길 바랍니다. ㅠㅠ

2. 네트워크 아키텍쳐의 실전 사례 분석

주의!
이 포스트에 언급된 게임들은 반드시 그렇게 작동된다고 책임지지 않습니다.
특히 해당 IP와 Port로 접속을 거는 것도 결코 책임지지 않습니다.

오래 전부터 네트워크를 분석하는 툴은 많았습니다.
기본 프로그램인 netstat도 훌륭한 도구이며(그 유명한 TCP/IP Illustrated 도 netstat로 실습하고 있습니다.)
약간의 관심만 가진다면 어떤 유명 게임이라도 클라이언트 상에서 어떤 과정을 거치는지 쉽게 확인할수 있습니다.
악용하지 않는다면 정말 좋은 공부가 됩니다.

이런 도구들이 있는데 유명 게임들의 네트워크 아키텍쳐를 전혀 모른다는 말은 개발자로써 관심이 없다는 말일 겁니다.
가끔 면접 볼때 무슨 게임에 몇년을 투자했다는 열정에 대한 자랑을 듣지만,
그 게임의 라이팅이나 네트워크를 짐작도 못하고 있으면 공돌이로썬 안타깝게 느껴집니다.

진짜 울고 싶은건 질문하는 사람이라구!!

진짜 울고 싶은건 질문하는 사람이라구!!


이 강좌에서는 비쥬얼스튜디오 이외에 앞으로 두가지 툴을 자주 쓰겠습니다.

1) TCPView
http://technet.microsoft.com/en-us/sysinternals/bb897437
오래전 MS에게 인수된 sysinternals의 TCPView입니다.
netstat과 거의 흡사하지만 GUI라서 보다 편리합니다.
예전에 날잡아 서버 개발자 PC를 검사하며 이것이 안 설치되어 있으면 갈구시던 어떤 실장님이 생각나네요(제가 아닙니다.).
그외 FileMon, RegMon도 클라이언트 플랫폼 개발자들에게는 필수 도구입니다.

2) WireShark
http://www.wireshark.org/
pcap 라이브러리를 사용하는 패킷 검사툴입니다.
사실 이것과 노가다만 있으면 어떤 게임이라도 프리서버를 만들어 내는 일은 가능합니다.
불가능 하다고요?
우리가 게임을 만들듯, 수백명이 한사무실에 모여 각자 팀별로 패킷만 분석한다면 어떨까요?
대륙의 판타지는 이렇게 만들어집니다.

2.1 C/S 모델
여기서 말하고픈 것은 C/S 아키텍쳐라도 절대로 서버 1대로만 접속하지 않는다는 점입니다.
MMORPG도 그 수많은 종류만큼 다양한 네트워크 아키텍쳐가 있습니다만, 간단한 카드류 게임으로 서버에 어떻게 접속하는지 보겠습니다.

로비에 접속

로비에 접속


 

로비서버로 짐작되는 XXX.XXX.XXX.214에 접속

로비서버로 짐작되는 XXX.XXX.XXX.214에 접속


 

로비에서 게임룸으로 들어왔습니다.

로비에서 게임룸으로 들어왔습니다.


 

게임서버로 짐작되는 XXX.XXX.XXX.172에 접속

게임서버로 짐작되는 XXX.XXX.XXX.172에 접속


이렇듯 C/S 모델이라도 최소한 두개의 서버를 번갈아 접속했다는 사실을 알수 있습니다.
그리고 TCP 이외에 UDP도 사용하고 있고요.
UDP는 연결지향이 아니니까 책에서 본대로 접속은 이뤄지지 않았습니다.

물론 서버는 이 두개 뿐만이 아닙니다.
직접 해보시면 서버 주소가 다를 것이고 테스트해볼때마다 다를 수도 있습니다.
이 말은 실제 각 로비서버와 각 게임서버는 여러 대가 있다는 의미입니다.
그리고 다른 서버로 접속했다 하더라도 같은 방에 있어야 합니다.

이를 위해서는

1) 서버간 통신을 해주는 서버가 필요
2) 어떤 서버로 연결할 것인지 알려주는 서버가 필요

라는 결론이 나옵니다. 그 구조를 클라이언트에서 알수는 없습니다만, 아키텍쳐는 나온 것이죠.
이러한 유추를 통해 각기 다른 월드나 지역으로 구분하는데도 유용하게 사용할수 있습니다.

2.2 P2P 모델

P2P의 대표 모델인 스타크래프트 배틀넷을 분석해보죠.
스타크래프트의 P2P 모델은 DirectPlay의 P2P 모델과 일치합니다.
DirectPlay를 그대로 가져다 쓴 것이라 여겨집니다.

P2P에서는 크게 자신이 세션(방)을 만드는 것과 다른 사람이 만든 세션을 검색해서 들어가는 두가지로 나뉩니다.
각 단계에서 소켓에서는 어떤 함수가 불려지는지 정리해보지요.

1) 내가 방을 만들어 접속하는 경우
1-1) TCP 소켓 생성

Winsock은 TCP/IP 이외에 다른 프로토콜도 사용가능합니다. Battle.net을 선택하는 순간 TCP/IP를 위한 준비를 합니다.

Winsock은 TCP/IP 이외에 다른 프로토콜도 사용가능합니다. Battle.net을 선택하는 순간 TCP/IP를 위한 준비를 합니다.

pSocket->Create(TCP); 와 같은 형태로 함수가 호출될 겁니다.

1-2) Connect()

로긴

로긴

버전업 체크 서버와 버전을 확인을 한후 로긴을 합니다.
이때 pSocket->Connect(배틀넷, 스타크래프트_확장팩); 형식으로 접속을 하게 됩니다.

1-3) recv()

배틀넷 서버에 접속

배틀넷 서버에 접속


배틀넷 서버에 접속했습니다.
recv() 함수가 작동되며 공지사항이 날라옵니다.

1-4) 로컬에 서버 소켓 생성

방을 만들면...

방을 만들면...


 

P2P를 위해 로컬에 서버가 만들어집니다.

P2P를 위해 로컬에 서버가 만들어집니다.

세션이 만들어졌습니다.
이때가 무척 중요합니다.
내가 세션을 만드는 것도 중요하지만 다른 유저들이 내가 만든 방을 검색하기 위해서
배틀넷 서버에게 내 세션의 정보를 알려줘야 합니다.
가장 중요한 것은 "서버인 나의 IP"입니다.

1-5) 세션 호스트로써 게임 시작
게임을 시작합니다.
이때 배틀넷과 접속을 끊습니다.
P2P답게 다른 유저들과 접속이 이뤄지고 있을 뿐 배틀넷과의 접속은 의미가 없기 때문이죠.

UDP 막 날라다님

UDP 막 날라다님


만약 세션 호스트(방장)이 게임에서 나가게 되면 세션 마이그레이션(session migration)이라는 과정을 거치며
P2P 세션 호스트의 자리를 다른 사용자에게 물려주게 됩니다.
안정적으로 이것을 수행하는 것이 꽤나 난이도 있는 일이며 홀펀칭과 함께 P2P 라이브러리가 해주는 중요한 역활입니다.
스타크래프트에서 일반 유저보다 방장이 나갈때 잠시 랙이 걸리는 이유입니다.

1-6) P2P close(), 배틀넷 connect()
방을 나간 사람은 P2P 세션에서 나가며 다시 배틀넷에 Connect를 하게 됩니다.
이때 이겼다, 졌다의 정보를 갖고 배틀넷에 send()를 합니다.
이때가 P2P가 보안에 취약할 때입니다. 실제 이겼는지 졌는지 배틀넷은 모릅니다.
져놓고서 이겼다는 패킷을 날려도 배틀넷은 알지 못합니다.

2) 다른 사람의 만든 방에 접속할 경우
2-1) 세션 목록 recv()
1-3) 까지는 똑같습니다.
가장 중요한 것은 배틀넷이 현재 접속을 요청하는 세션 목록을 나타내는 것입니다.

P2P 서버가 해주는 가장 중요한 일

P2P 서버가 해주는 가장 중요한 일


2-2) 세션에 참여 P2P connect
배틀넷과 접속을 끊고 해당 세션 호스트의 IP로 접속을 하게 됩니다.

배틀넷과 접속을 끊고 P2P 세션에 connect()

배틀넷과 접속을 끊고 P2P 세션에 connect()


2-3) 게임 시작
세션 호스트라는 것이 아니면 네트워크 상으로는 똑같습니다.

마땅한 짤이 없어...지만 이건 스타2인데...

마땅한 짤이 없어...지만 이건 스타2인데...



2-4) P2P close(), 배틀넷 connect()
게임을 나가게 되면 P2P 세션을 닫고 배틀넷으로 접속합니다.
이 역시 1-6)과 같습니다.

3. 홀펀칭
P2P는 세션 마이그레이션 이외에도 NAT이 가장 골치꺼리입니다.
NAT 뒤에 있는 IP는 실제 IP가 아니기 때문에 밖에서 들어올 수 없는 것이죠.
공유기에 따라 특정 IP를 밖으로 노출 시키는 경우도 있고 아닌 경우도 있습니다.
어찌되었건 게임 서비스를 하는 입장에서는 NAT 특성에 관계없이 연결을 만들어줘야 합니다.

다행히도 이러한 홀펀칭에 대해서는 denoil님께서 멋지게 정리를 해주셔서 (http://gamedevforever.com/47)
해당 포스트를 참조하시면 될 것 같습니다. ^^

홀펀칭 역시 제 블로그(http://rhea.pe.kr/)에서도 2-1 편으로 다시 정리하겠습니다.
UDP 예제도 이번 포스트 소스로 넣어야겠군요...

자, 이번 포스트를 통해 소켓 사용법 이외에 네트워크 게임 개발자로써 고민해야할 1차적인 아키텍쳐를 이야기해봤습니다.
강조하고픈 것은 아키텍쳐에 게임을 맞추지 말고,
게임에 따라 유연한 아키텍쳐를 생각해내고 업데이트에 따라 유연하고 쉽게 바뀔 수 있는 자세를 가져야 한다는 것입니다.
좋아하는 게임이 있으면 어떤 네트워크 아키텍쳐를 갖고 있는지 최대한 유추해보시길 바랍니다.
그리고 PC게임 뿐만 아니라 스마트폰 게임이나 콘솔게임기를 추적해보는 것도 좋은 공부가 됩니다.

다음 시간에는 서버와 절대로 떼어놓을 수 없는 Database를 살펴보겠습니다.
아직도 게임을 만들 시기는 아닙니다.

4. 더 생각해볼꺼리
1) 오늘 예제로 등장한 C/S게임과 스타크래프트의 네트워크 연결 순서도를 그려보세요.
물론 소켓 함수도 함께 적어보세요.

2) 자세히 보시면 스타크래프트1의 배틀넷은 DirectDraw surface가 아니라 일반 Dialog입니다.
(커서가 윈도우 커서로 바뀌죠?)
저도 그랬지만 Surface 위에 Dialog 나 윈도우 stuff들을 올리는 것은 쉽지 않았습니다.
이는 지금도 마찬가지인데 각자 UI 컨트롤을 위해 노가다 헀던 경험담들을 풀어봅시다.
선수끼리 숨기지말고요~

내용은 맘대로 퍼갈수 있지만 동의없는 수정은 안되며 출처(http://www.gamedevforever.com/ , http://rhea.pe.kr/ )를 명시해주세요.

 

 

출처 : http://rhea.pe.kr/498
원문 : http://www.gamedevforever.com/39

안녕하세요? 요양과 잉여짓으로 바쁜 Rhea Strike 입니다.
정작 당분간 하지 않을려했던
잉여 프로그램들은 짜고 있지만 가장 맘먹은 동인지 원고와 짤 제작, 여친 만들기 등이 늦어져 무척 가슴 아픈 나날입니다.

다들 쟁쟁한 주제들과 현업에서 연구하신 소재들로 막강한 화력을 자랑하시지만
실력이 딸려 제가 준비한 것은 네트워크 게임을 만드는 튜터리얼 연재입니다.
이 연재를 시작하기전 무슨 주제로 어떻게 이어갈까 고민을 잠시 했는데요,
잠시 이 링크 http://rhea.pe.kr/493 를 읽어주시고 연재글을 봐주시면 감사하겠습니다.

연재의 초기는 기본적인 채팅으로 시작될 것입니다.
이는 네트워크 프로그래밍에 익숙하지 않는 분들과 있을지도 모를 학생들을 위한 것이기도 합니다만,
매 연재 속에 점점 단순 채팅 프로그램이 게임과 아키텍쳐로 점차 커져가며
퇴근길 지하철에서 전체 게임을 위해서 한번 곱씹어 생각해볼만한 꺼리를 던져드리는게 제 목적입니다.

자, 그럼 지루한 서론을 마치고 우선은 모두들 알고 계신 내용이라도 복습의 의미로
기초부터 시작해보지요. ...역시 지루하군요.

짤에 별다른 의미는 없습니다만 이런 여친을 찾고 있습니다. 도움을 바랍니다.

짤에 별다른 의미는 없습니다만 이런 여친을 찾고 있습니다. 도움을 바랍니다.


1. 윈속의 역사
이미 게임을 하나 운영하고 있는 곳이라면 많은 것이 갖춰져 있습니다.
개발자 이외에도 DB, 서버, 패치 시스템, 그리고 그것을 돌려주는 여러 DBA, SE분들이 있습니다.
그러나 아무 것도 없는 곳에서 새로 온라인/네트워크 게임을 만든다면 맨땅에 헤딩을 해야 합니다.

우선 기획서가 나오고 DB라던가 여러 가지 인프라들이 먼저 있어야할 것이지만,
가장 단순하게 윈도우 서버와 클라이언트부터 만든다고 가정합시다.
자, 그럼 서버는 어떻게 만들어야 할까요?
서버를 만들기 전에 서버와 클라이언트에는 어떤 "Winsock Model"을 사용할런지부터 결정해야 합니다.

원래 소켓은 Windows 운영체제가 아니라 BSD UNIX에서 먼저 만들어졌습니다.
그래서 초창기 윈도우 3.1 같은 경우에는 소켓(http://www.joinc.co.kr/modules/moniwiki/wiki.php/man/12/BSD%20socket)
이 아예 존재하지 않았습니다.

이는 단순 소켓 지원 여부를 떠나 당시 마이크로소프트(앞으로 MS)의 중요한 의사 표방이기도 합니다.
소켓은 TCP/IP, UDP를 위한 라이브러리이고 TCP/IP, UDP같은 프로토콜은 바로 인터넷의 기반이 되는 프로토콜들이죠. 모든 것을 집어삼킨 HTTP 역시 TCP/IP 80번 포트를 이용한 텍스트기반 프로토콜 아니겠습니까?

다시 말해, MS는 현재의 인터넷이 이리 사용될지 몰랐습니다, 무려 90년대 중반까지도요!
MS는 소켓과 TCP/IP가 아닌 자신들의 프로토콜로 MS-Network라는 현재의 인터넷과 비슷무리하지만 다른 개념을 만들고 싶었습니다.

그 망상은 Windows 2000 이 등장하면서 공식적으로 사라졌는데 \\로 접근하던 다른 PC접근과 네트워크 공유를 NetBIOS(NetBEUI) 설치 없이 TCP만 설치하면 되도록한 것이 그 증거(?)라고 볼수 있습니다. 정확하게 말하면 NetBIOS over TCP/IP 이란 개념인데 아뭏든 90년대에도 MS는 인터넷도, TCP도, BSD 소켓도 반대! 그냥 MS껄로 다 정ㅋ벅ㅋ할꺼야!!였었습니다.

그래서 Win 3.1에서 Netscape로 웹서핑을 하던 우리들은 Win 3.1에는 없는 TCP/IP 프로토콜을 쓰기 위해
트럼펫 윈속(http://www.trumpet.com.au/index.php/downloads.html) 을 따로 설치해 썼었었습니다.
진짜 일반 사용자가 쓸수 있는 MS표 소켓이 나오는 것은 Win95 때부터입니다.

추억 돋는 화면 하나 더! http://www.loblolly.net/~rddecker/helppages/win31trmwns.htm



....................




...........





.....


..


그러나 어쩌겠습니까?
모두가 알다시피 인터넷(다시 말해 TCP/IP과 그것을 쓰기 위한 BSD Sockets)이 대세가 되었는데요.


이 당시 빌횽의 마음...

이 당시 빌횽의 마음...









할수 없이, MS는 BSD 소켓과 똑같은 윈도우용 소켓 라이브러리를 제작합니다.
BSD 소켓 4.3에 기반해 1993년 WinNT 3.51과 함께 Winsock 1.1을 공개합니다.
즉, Winsock은 WINdows + SOCKet의 약자지요.

정말로 이때 빌횽은 전세계 개발자들에게 이말을 들었습니다.

정말로 이때 빌횽은 전세계 개발자들에게 이말을 들었습니다.




이 윈속 1.1은 놀랄만큼 BSD 소켓과 동일합니다.
고인이신 스티븐슨의 UNIX Network Programming에 있는 소스 대부분이 헤더 파일만 약간 바꾸면 그대로 돌아갈 정도입니다.

네트워크 게임계의 프로메테우스, 古 리차드 스티븐슨

네트워크 게임계의 프로메테우스, 古 리차드 스티븐슨

이는 다이렉트X 초창기의 모습과 유사합니다. DOS 게임 개발자들에게 복잡한 Windows Procedure와 콜백을 잘 몰라도 DOS 게임을 그대로 포팅할수 있도록 한 배려와 비슷한 모습입니다.

하지만 이때까지도 MS는 TCP/IP의 가능성을 잘 몰랐습니다.
...그래서 Winsock 1.1을 사용하는 Windows 서버는 ....상당히 구렸습니다.
윈도우는 서버로는 절대 안된다는 말이 이때부터 흘러나왔죠.

그러나 1995년 WinNT 4.0의 등장과 함께 선보인 Winsock 2.0부터 상황은 달라지기 시작합니다.
아키텍쳐부터 싹 달라졌습니다.
1.0과의 호환성은 100% 유지하면서 Windows에 최적화된 진짜 Winsock이 등장한 것입니다.
(달라진 아키텍쳐로 "개인방화벽" 프로그램이 만들어질 수 있었습니다. 자세한건 "SPI"로 검색을 ^^)

오오미 윈속이랑께~!!

오오미 윈속이랑께~!!

현재 우리가 주력으로 사용하는 Winsock은 16비트 모드가 제거되어 1996년에 발표된 2,2를 사용하고 있으며
Win8이 등장할때 Winsock에 Registered IO extensions 이 추가된다고 하는데 간만에 Winsock에 새로운 기능이 추가되는 것이라 기대가 큽니다.

2. 윈속 모델

모델의 좋은 사례, Winsock에게도 공식 모델이 필요합니다.

모델의 좋은 사례, Winsock에게도 공식 모델이 필요합니다.


드디어 오늘 기초의 핵심인 윈속 모델 이야기를 하겠습니다.
안타깝게도 윈속이 버전업이 되었다고 해서 윈속의 성능이 공짜로 올라가는 것은 아닙니다.


네트워크 프로그래밍에서 첫쨰 난관은 언제 "1) 누가 서버에게 Connect를 해 올줄 모른다"는 점입니다. 그리고 이때 클라이언트가 Connect를 해오는 순간, 아주 빠르게 accpet()를 해줘야 합니다. 접속이 수천개가 되면 이 작업 역시 딜레이가 걸리고 컨텍스트 스위칭이 걸립니다.
그런 다음, 일단 양쪽이 연결이 되면 "2) 서버든 클라든 언제 상대방의 메시지를 듣기 위해 recv()를 해야할지 모른다"는 점입니다(아시겠지만 연결을 끊는 close() 역시 사실은 상대방에게는 recv()입니다.)

언제 이벤트가 오는지 모르는 싯점을 체크해봤습니다.

언제 이벤트가 오는지 모르는 싯점을 체크해봤습니다.

이미지 출처 : http://publib.boulder.ibm.com/infocenter/iseries/v5r3/index.jsp?topic=%2Frzab6%2Frzab6connectionor.htm

사실 게임 클라이언트처럼 소켓 5개 정도에서는 큰 차이가 없습니다만,
서버는 한 프로세스가 수백~수천개의 접속을 관리해야 합니다.
이를 위해 단일 thread를 돌리는 방법으로는 고작 수십명이면 금방 한계에 찹니다.
아무리 서버장비가 좋아도 똑같습니다.
왜 단일 thread는 안될까요?
thread라는게 마법은 아닙니다. 단순히 CPU 한계치까지 일을 시킬 뿐, 계속 루프를 돌며 찌질하게 검사하는 역활 밖에 할 수 없습니다.

좋은 서버란 가장 적은 thread와 CPU를 사용해 가장 많은 접속을 빠르게 처리해줄수 있어야 하며 이를 위해 두가지 개념을 먼저 알아야 합니다.

우선 비동기(asynchronous )라는 개념이 들어갑니다.
쉽게 말해 계속 루프를 돌며 검사하는게 아니라 클라이언트에게 접속요청이 왔거나 메시지가 왔을때에만
해당 소켓에게 알맞은 작업을 해주는 것입니다.

그래서 비동기 Winsock을 위해 4가지 모델이 고려되었습니다.







이중 알맞은 Winsock Model 네명을 고르시오.

이중 알맞은 Winsock Model 네명을 고르시오.






...는 아니고...





모델명 특징 기타
Window Message Select
(WSAAsyncSelect)
소켓 이벤트를 윈도우 메시지를 이용해 알려준다. 윈도우 메시지를 이용하므로 반드시 윈도우가 생성되어야 하며 MFC의 CSocket 클래스가 바로 이 모델.
Kernel Event Select
(WSAEventSelect)
소켓 이벤트를 커널 이벤트로 알려준다. 한 객체당 최대 64개의 이벤트 밖에 못쓰므로 서버로 쓰기 위해서는 코드가 쓸때없이 복잡해짐.
Overlapped I/O
(Overlapped)
소켓 이벤트를 비동기 읽기/쓰기를 위한 오버랩 구조체를 이용해 알려준다. 위의 둘과 달리 Overlapped와 IOCP는 Win95, 98에서는 안됩니다.

이 기법은 파일에 비동기로 읽기쓰기를 같이 하기 위함이었으나 소켓이든 파일이든 둘다 같은 HANDLE 이잖아요? ^^

역시 MS의 꽁수의 결정체라 불릴만 합니다.
Overlapped I/O + IOCP
(IOCP)
위의 방식에 더해 커널 큐잉을 통해 소켓 이벤트를 통보받는다. 사실상 윈됴에서 서버는 이넘으로 정해져있다. C#에서 비동기 선언해도 IOCP가 만들어진다.

결론은 서버는 IOCP가 정답입니다!
...이런 모델들입니다.


두번째는 넌블로킹(non blocking)개념입니다.
단일 thread가 아닌 비동기 서버를 짰다고 합시다.
이때 어떤 이벤트가 일어나면 비동기로 OS가 서버에게 알려줍니다.
그러나 send(), recv() 같은 함수는 블로킹(blocking)함수 입니다.
send(), recv() 작업이 끝날 때까지 서버 프로그램은 다음 일을 할수 없습니다.
이때 WSASend(), WSARecv같은 넌블로킹 함수로 대체한다면, 작업이 끝나기 전에 서버는 다음 작업으로 진행될 수 있습니다.

아마 넌블러킹 함수는 네트워크 프로그래밍에서 처음 보신 분들도 있을 것이지만,
수많은 I/O관련 함수들의 고급은 전부 넌블러킹으로 흘러가게 됩니다.
넌블러킹 함수는 어쩔수 없이 Callback 함수가 반드시 뒤따라갑니다.
그래서 처음 접하면 조금 어렵습니다............................................가 아니라 실은 많이 어렵습니다,
거기에 Overlapped나 IOCP같은 비동기 통보까지 더해지면 아주 복잡해집니다.

다행히 클라이언트에서 주로 쓰이는 WSAAsyncSelect 모델과 WSAEventSelect 모델에서는 넌블로킹이 그리 중요한 개념은 아닙니다. 유선 인터넷이 하도 빨라서요...
클라이언트에서 넌블로킹을 잘못 쓰면 소켓 응답 오기 전까지 게임 프로그램 자체가 위험해질수도 있고
그 사이 화면 UI처리같은 다른 할일들도 신경을 써야 합니다(<-이거 은근 고급 토픽입니다.).

그렇다고 클라이언트=블로킹이 절대 아닙니다.
최근 스마트 디바이스에서 SNS클라이언트와 SNG와 같은 게임에서는 불안한 3G 네트워크 때문에
요즘은 클라이언트도 비동기 + 넌블로킹이 대세입니다.

3G가 워낙 느리고 자주 끊기니, 일단 클라이언트에서는 send()한 것으로 치고
유저에게 다음 작업을 할수 있도록 해주는 것입니다.
혹시 안된다면 나중에 에러 메시지가 뜨며 다시 하라고 알려줍니다.

SNG를 안하시는 분들도 트위터같은 앱에서 자주 보셨을 것입니다.
재미있게도 이런 처리 방식은 트위터 웹페이지에서도 확인할 수 있습니다.
물론 저도(사실은 밑에 팀원 갈궈서 하게 했습니다... >_<;;; ) SNS 만들때 이렇게 했고요.

만약 단순 블로킹이라면 이런 상황 자체를 볼수 없을 것입니다.

만약 단순 블로킹이라면 이런 상황 자체를 볼수 없을 것입니다.


이는 We Rule같은 게임이 네트워크가 불안정할때 쉽게 확인될수 있습니다. 단순해 보이는 SNG도 3G라는 현실로 제법 복잡한 네트워크 구현 기술을 알아야 합니다.

...이슬이...드립 치고 싶습니다.



3. 오늘의 소스
오늘의 소스는 간단한 클라이언트/서버 소스입니다.
클라이언트는 MFC로 만들었고 Winsock Model 역시 CSocket, 즉 윈도우 메시지 방식입니다.
서버는 boost::asio로 짰습니다. 기본 TCP 서버를 그대로 썼습니다.
단, 한 파일로 설명된 소스를 보기 좋게 클래스별로 나눠놨습니다.
이 정도면 네트워크 프로그래밍에 익숙하지 못한 초보분이라도 약간의 노력이면 다음 시간부터 따라오실수 있을 것입니다.

이 간단한 프로그램들로 네트워크 게임을 위한 첫 삽질이 시작될 것입니다.




4. 더 생각해볼꺼리

1) 심심하고 정말정말 할일이 없는 날, 단일 thread 방식의 채팅 서버와 윈도우 메시지 방식의 채팅 서버를 만들어 최대 몇개의 클라이언트에게 원할하게 메시지를 돌려주는지 직접 재어보세요.
2) 클라이언트가 블로킹으로 작동되어야할 경우와 넌블로킹으로 작동되어야할 경우를 생각해보세요.
3) 클라이언트가 블로킹과 넌블로킹, 모두가 동시에 필요하다면 소켓 라이브러리를 어떻게 만들어야할까요?
(힌트 : MFC에서 CSocket 와 부모 클래스인 CAsyncsocket를 살펴보세요.)
4) 실제 게임회사의 면접에서 IOCP의 동작 메커니즘을 구두로 답변하기는 무척 어렵습니다.
그래서 저는 이렇게 묻습니다,
"왜 IOCP 소스에는 recv() 함수가 두번 적혀있나요?"
여러분은 머라고 대답하시겠습니까?



내용은 맘대로 퍼갈수 있지만 동의없는 수정은 안되며 출처(http://www.gamedevforever.com/ , http://rhea.pe.kr/ )를 명시해주세요.

 

 

출처 : http://rhea.pe.kr/494

출처 : http://blog.naver.com/baek2187/150110320251

codesign.zip

1. ActiveX 만들기

 

비주얼스튜디오에서 ActiveX 를 만드는 방법은 두가지가 있다.

응용프로그램 마법사로 프로젝트를 이용하여 MFC ActiveX Control 프로젝트 또는 ATL Project 프로젝트로 만든다.

  1. MFC ActiveX Control
    • 프로젝트 생성하고 빌드하면 .OCX 라는 DLL이 만들어진다. 이 OCX 파일을 CAB에 포함하여 웹페이지에 링크하면 된다.
    • MFC를 이용하여 컨트롤을 개발할 경우에는 OLE를 전혀 모르는 프로그래머들도 원하는 형태의 OCX 컨트롤을 구현하기 쉽다.
    • 단 지, MFC로 ActiveX를 만들면 코드 사이즈가 커지며, 그것은 MFC가 컨트롤에 대해서 COleControl 클래스를 기반으로 생성해 주기 때문에 기존의 OLE 컨트롤 사양에서 필수적으로 구현해 주도록 한 부분을 모두 포함하고 있기 때문이다. 또한, MFC의 부수적인 Run-time DLL도 오버헤드로 작용할 수 있다.
    • CAB 배포시 MFC관련 DLL을 함께 포함하고 inf 파일에 명시해야 한다.
  2. ATL Project
  • MFC 프로젝트에 비해 배포에 필요한 DLL 용량이 작아서 효율적이다.
  • MFC 프로젝트에 비해 컨트롤 구현을 ATL로 직접 구현해야 하기 때문에 비교적 힘들다.
  • MFC를 이용한 UI가 거의 없고 배포 용량을 줄이는 프로젝트 구현에 적합하다.

MFC 기반으로 ActiveX 만들기

  1. MFC ActiveX Control 프로젝트를 생성한다.
  2. 프로그래밍후 빌드하면 OCX 파일이 생성된다.
  3. MFC 메서드와 HTML과 메서드 커뮤니케이션시에 안전하지 않는 컨트롤 실행에 대한 윈도우 경고창이 뜰 경우 안정성을 보장하는 컨트롤 을 제작한다.

개발 참조:

ActiveX 강좌

MFC ActiveX 컨트롤 만들기

Visual studio 2008 에서 ActiveX만들기

ATL 기반으로 ActiveX 만들기

  1. ATL 프로젝트를 생성한다.
  2. 솔루션의 프로젝트에서 Add Class로 ATL Control을 하나 추가한다. (아래는 추가시 옵션이다)
    1. 추가시 Options
      • Control type: 보통은 Standard control로 설정한다. Windows Form과 비슷한 컨트롤을 작성하려면 Composite control을, DHTML을 호스팅해서 UI를 구성하려면 DHTML을 사용한다.
      • Minimal control: 최소한의 COM 인터페이스만을 구현하도록 한다. 이 예제는 IE에서만 동작하면 되므로 체크해 두었다. VB나 VC등으로 만든 다른 COM Host어플리케이션에서 사용되어야 하는 컨트롤이라면 체크하지 말자.
      • Connection points: 컨트롤이 외부에 이벤트를 공개해야 한다면 선택하자. 예제에서는 이벤트 사용 예제를 위해 체크해 두었다.
    2. 추가시 Interfaces
      • IObjectSafety: 컨트롤이 스크립트, 초기화 등에 안전함을 컨테이너가 인식할 수 있도록 한다.
      • IPropertyNotifySink: 컨트롤에서 변경된 속성을 즉시 사용할 수 있도록 해 준다.
      • IProvideClassInfo2: 이벤트 사용을 위해서는 반드시 필요하다. Connection Point를 구현하는 경우라면 반드시 포함시키자.
      • IQuickActivate: 콘트롤을 보다 빨리 활성화 시킨다.컨테이너는 컨트롤에 구현된 IQuickActivate::QuickActive메서드를 호출 QACOTAINER구조체정보를 매개변수로 컨트롤에 넘겨준다.
      • ISupportErrorInfo: 컨트롤에서 발생한 예외(Exception)을 컨테이너가 처리할 수 있도록 해 준다.

개발 참조:

ATL ActiveX 만들기 - Part1. 프로젝트 구성

ATL ActiveX 만들기 - Part2. 컨트롤 구현

ATL ActiveX 만들기 - Part3. 이벤트(Connection point) 구현

ATL ActiveX 만들기 - Part4. 관리자권한 UAC Elevation

안정성을 보장하는 ActiveX 컨트롤 만들기

MFC는 기본적으로 위자드에서 생성된 컨트롤에 스크립팅과 컨트롤 초기화를 위한 안전처리가 되어있다. IE에서 보안이 보통 이상인 경우 컨트롤이 안전하지 않다는 메시지가 출력될 것이다.

해결하는 방법은 두 가지로, IObjectSafety 인터페이스를 구현하는 것이고 다른 하나는 컨트롤의 DLLRegisterServer 함수안에 레지스트리에 안전표시를 하도록 하는 것이다.

HOWTO: MFC 컨트롤을 스크립트 사용에 안전(Safe for Scripting)/초기화에 안전(Safe for Initialization)으로 표시

안정성을 보장하는 ActiveX 컨트롤 제작

ActiveX Control 보안처리

액티브X 생성에서 배포까지

디버거 설정 및 디버깅하기

ActiveX 컨트롤은 웹페이지상에서 실행되기 때문에 일반 어플리케이션과는 디버깅을 다르게 설정해야 한다.

  1. 프로젝트 속성(Property)에서 Debugging - Debugger to launch 에서 Web Browser Debugger를 선택한다.
  2. HTTP URL 부분에 $(ProjectDir)컨트롤이름.htm 설정한다.
  3. F5로 디버거를 실행하면 브라우저가 뜨고 ActiveX 가 작동하며 디버깅이 가능해진다.

$(ProjectDir)는 프로젝트 파일이 저장되어있는 로컬 경로를 의미하며, 이곳에는 만들려고 하는 컨트롤의 OBJECT태그가 포함된 컨트롤이름.htm파일이 자동으로 생성되어 있다.

ActiveX 테스트를 위한 ActiveX Control Test Container 사용 방법

Visual Studio 2008 에는 작성된 Active X를 테스트를 위한 ActiveX Control Test Container 툴(TstCon32.exe)이 포함되어있지 않습니다.

VS 6.0에서는 기본 툴로 제공 되었으나 닷넷부터는 제공되지 않아 소스만 구할수 있으므로 빌드해야 한다.

첨부 파일에 실행파일만 첨부했지만 소스가 필요하다면 위에 제목으로 링크따라 가면 다운로드할 수 있다.

이제 ActiveX 프로젝트를 디버깅할 때 Executable For Debug Session 창의 Executable file name에 C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools\TstCon32.exe 를 선택하여 사용 가능하다. (나중에 project property 창에서 Debugging > Command 에서 변경할 수 있다.)
C:\Program Files\Microsoft Visual Studio 9.0\Common7\Tools 폴더에 아래 첨부파일을 넣어서 사용한다.
또는, ActiveX를 Regsvr32 명령을 통해 OS에 등록 하신 후, 직접 TstCon32.exe 실행 후 Edit->insert New Controls ... 를 이용하시면 된다.

2. INF(.inf) 파일 만들기
섹션 편집

INF 파일은 컨트롤을 실행하거나 다운로드해야 하는 파일(DLL 또는 기타 OCX)을 지정하는 텍스트 파일이다. INF 파일을 사용하면 필요한 모든 파일을 하나의 압축된 CAB 파일로 묶을 수 있다. 기본적으로 사용자의 하드 디스크에 있는 기존 파일과 버전 번호가 같은 파일은 다운로드하지 않는다.

CAB 파일을 생성하기에 앞서 먼저 INF 파일을 만들어야 한다. INF 파일에는 Control과 함께 클라이언트측으로 다운로드 되어야 하는 파일들에 대한 정보가 저장된다. 비주얼 베이직은 자동으로 생성해주지만 VS일 경우 수동으로 메모장을 이용하여 작성해야 한다.

아래 내용은 inf 파일 예제이다. text.ocx 파일이 ActiveX 파일이며 기타 dll은 MFC 실행에 필요한 DLL 파일이다.

INF 파일 작성에 대한 자세한 내용은 아래 참조 링크를 보면 자세히 나와있다.

; ========================= test.inf ========================

; This .inf file will control the installation of the MFC test
; control. This control has been compiled with Visual C++ version 4.2.
; The FileVersion tags in the dependent DLLs section on this file
; reflect this requirement.

[version]
; version signature (same for both NT and Win95) do not remove
signature="$CHICAGO$"
AdvancedINF=2.0

[Add.Code]
test.ocx=test.ocx
; These are the necessary supporting DLLs for MFC 4.2 ActiveX Controls
mfc42.dll=mfc42.dll
msvcrt.dll=msvcrt.dll
olepro32.dll=olepro32.dll

; dependent DLLs
[msvcrt.dll]
; This is an example of conditional hook. The hook only gets processed
; if msvcrt.dll of the specified version is absent on client machine.
FileVersion=6,0,8168,0
hook=mfc42installer

[mfc42.dll]
FileVersion=6,0,8168,0
hook=mfc42installer

[olepro32.dll]
FileVersion=5,0,4261,0
hook=mfc42installer

[mfc42installer]
file-win32-x86=<LINK TYPE="GENERIC" VALUE="http://activex.microsoft.com
/controls/vc/mfc42.cab">http://activex.microsoft.com/controls/vc
/mfc42.cab</LINK>
; If dependent DLLs are packaged directly into the above cabinet file
; along with an .inf file, specify that .inf file to run as follows:
;InfFile=mfc42.inf
; The mfc42.cab file actually contains a self extracting executable.
; In this case we specify a run= command.
run=%EXTRACT_DIR%\mfc42.exe

; thiscab is a keyword which, in this case, means that test.ocx
; can be found in the same .cab file as this .inf file
; file-win32-x86 is an x86 platform specific identifier
; See the ActiveX SDK - ActiveX Controls - Internet Component Download -
; Packaging component code for automatic download

[test.ocx]
file-win32-x86=thiscab
; *** add your controls CLSID here ***
clsid={0D886696-C7CE-11D3-A175-08002BF17507}
; Add your ocx's file version here.
FileVersion=1,0,0,1
RegisterServer=yes

세미콜론(;) : 주석문을 표시한다.
"[Add.Code]" : 설치할 파일들을 나열한다. inf 내에 등록 하려는 ocx 는 [Add.Code] 섹션 맨 위 제일 위에 적어준다. 설치되는 순서가 중요하다.

"hook"은 설치할 방법을 설정하는 부분의 Title을 입력한다.

"thiscab"은 이 INF를 포함하는 CAB 파일을 의미하는 키워드이다.

"file-win32-x86"에 thiscab 대신 아래와 같이 절대 경로 또는 상대 경로를 지정하여 HTTP 위치에서 필요한 DLL을 다운로드할 수 있다.

file-win32-x86=http://example.microsoft.com/mydir/NEEDED.DLL 


FileVersion은작성한 OCX 파일의 버전을 입력(Resource에서 설정한 값과 같이 입력)한다. 설명상 FileVersion은 ActiveX 파일을 작성하여 배포하던 중 버그를 발견하여 수정하여 재 배포를 할 때 이 파일 버전을 높여 주면 Client에서 알아서 다시 다운로드를 받는다. 버전 표기시 쉼표로 꼭 구분해준다. (제대로 다운로드 되지 않음)

Windows 탐색기에서 마우스 오른쪽 단추로 클릭하여 파일의 버전 번호를 확인할 수 있다.

"DestDir"은 파일을 로드할 디렉터리이며, 11은 WINDOWS/SYSTEM 또는 WINNT/SYSTEM32 시스템 디렉터리를 지정하며, 10은 WINDOWS 또는 WINNT Windows 디렉터리를 지정합니다. 일반적으로 DestDir는 지정하지 않는데, 그런 경우 코드는 고정된 OCCACHE 디렉터리에 설치됩니다.

위의 내용 중 test를 자신이 작성한 ActiveX 컨트롤의 이름으로 변경하고

"clsid"는 설치될 컨트롤의 CLSID입니다.

clsid={0D886696-C7CE-11D3-A175-08002BF17507} 를 자신이 작성한 컨트롤의 clsid로 수정한다.

clsid는 ActiveX 컨트롤을 만든 디렉토리의 .idl 파일을 열어 가장 마지막에 나와 있는 제작한 ActiveX 컨트롤의 id를 입력하면 된다.

CLSID란???
Class Identifier로서 COM 개체를 식별하는데 사용되는 GUID 값이다. 그렇다면 GUID란 또 무엇인가? GUID(Globally Unique Identifier)란 128비트의 크기를 갖는 구조체로서 전세계적으로 시간과 장소에 관계없이 고유하다고 보장할 수 있는 어떤 값을 나타내는 식별자로 사용된다. UUID(Uinversally Unique Identifier)라고도 한다. COM에서 Interface와 개체의 고유성을 보장하기 위해 사용되는 값이라고 알아두자. 더욱 자세한 내용을 알고 싶은 독자는 COM 관련 서적이나 MSDN을 참고하길 하란다.

INF 파일을 만들어서 아래 CAB 파일 생성에 포함시켜야만 배포시 웹페이지에서 ActiveX 다운로드할 때 참조된다.

참조 링크:

CAB 파일 만들기.

Code Sign과 배포

CAB 파일 작성법

3. 디지털 서명(Code Sign)된 CAB 파일 만들기
섹션 편집

ActiveX Control을 만들어서 웹페이지에 올리기 위해서는 반드시 Code Sign을 해야한다.간단히 말해 Code Sign은 보안 문제 때문에 필요한 작업이다.

웹페이지에 올려진 Control은 Client의 시스템에 설치된 후 실행되기 때문에 항상 위험성을 내포하고 있다.

따라서 Internet Explorer는 Control을 다운로드 받을때 Control이 디지털 서명(Digital Signature)을 가지고 있는지를 검사한다.

디지털 서명이란 해당 Control을 제작한 회사를 나타내는 바이트 문자열이다. 또한 Control은 디지털 서명을 확인할 수 있도록 보안증(Certificate)이라고 하는 또 다른 바이트 문자열을 제공해야 한다.

개발기간중에는 임시로 테스트용 디지털 서명을 만들어서 사용할 수 있다.

정식 서비스 배포시에는 유료로 제공되는 인증된 디지털 서명 파일이 필요하다.

CAB 파일 생성과 디지털 서명에 필요한 툴입니다. (첨부파일에 있음)

CabArc.exe: Cabinet Archive(CAB)파일을 생성해 주는 프로그램.
SignCode.exe: CAB 파일을 비밀키와 인증서로 싸인해 줍니다. CAB파일에 코드사인을 합니다.
ChkTrust.exe: 코드사인 작업이 잘 수행되었는가 검증해 주는 프로그램 입니다.
MakeCert.exe: 테스트용 인증서를 만들어 주는 프로그램 입니다.
Cert2Spc.exe: MakeCert로 만들어진 시험용 인증서를 사인하는 작업에 사용될 수 있도록 변환하는 프로그램.

  1. 배포에 필요한 CAB 파일 생성
    • CABARC -s 6144 n MYCTL.CAB NEEDED1.DLL NEEDED2.DLL MYCTL.OCX MYCTL.INF
    • CABARC는 MYCTL.CAB라는 CAB 파일을 만듭니다.
    • 소스 파일(INF, OCX 및 DLL 파일)이 들어 있는 디렉터리에서 CABARC를 실행해야 한다.
    • CAB 파일에 보관될 파일은 INF 파일에 나열된 순서대로 명령줄에 나열되어야 한다.
    • 위 예제의 INF 파일에서는 NEEDED1.DLL, NEEDED2.DLL, MYCTL.OCX의 순서로 나열되어야 한다.
    • -s 옵션은 캐비닛에코드 서명을 위한 공간을 예약한다. n 명령은 CAB 파일을 만든다는 것을 지정한다.
    • 라인 맨 뒤에 INF 파일은 위에서 CAB 파일을 위해 수동으로 만들어진 .inf 파일이다.
  2. 디지털 서명 (테스트) 파일 만들기 (유료 인증된 디지털 서명 파일이 있을 경우 테스트용으로 만들 필요 없음)
    • makecert -n "CN=MySoftwareCompany" -sv MyKey.pvk MyCert.cer
    • pvk 라는 개인 키 파일과 .cer 라는 회사 인증서 파일을 테스트용으로 만든다.
    • 생성시 개인 키 암호를 물어보는데 아무거나 설정하면 되면 나중에 CAB파일에 코드 사인할때 입력해야 한다.
  3. 디지털 서명 cer 파일로 spc 파일 만들기
    • cert2spc MyCert.cer MyCert.spc
    • 테스트를 위한 SPC(소프트웨어 게시 인증서)를 만든다.
  4. CAB 파일에 디지털 서명 파일로 코드사인하기
    • signcode -v MyKey.pvk -spc MyCert.spc MYCTL.CAB
    • 개인 키 암호 입력 대화 상자가 생성되고 위 과정에서 입력한 암호를 입력하면 .cab 파일에 디지털 서명한다.
  5. 테스트 디지털 서명이 인식되도록 클라이언트 시스템에 설정하기 (한번만 하면 됨)
    • SETREG 1 TRUE
    • 해당 클라이언트에서 보증 확인 과정을 제어하는 레지스트리 키를 설정하는 것이다.
  6. 디지털 서명된 CAB 파일 이상없는지 확인하기
    • chktrust MYCTL.CAB

(MSDN) 다음은 서명된 CAB 파일을 만드는 단계입니다.

  1. Software Publisher Certificate 얻기(한 번만 수행하면 됨)
  2. CAB 파일 만들기.
  3. CAB 파일 서명.
  4. 웹 페이지에 서명된 CAB 파일 포함(선택적)

참조 링크:

MFC 및 ATL 컨트롤을 위한 서명된 CAB 파일 만들기

Code Sign과 배포

CAB 파일 작성법

배포하기(Cab 파일 작성법)

signcode.exe 사용법 : DOS 버전
signcode.exe 사용법 : 윈도우 버전

cabarc.exe사용법 : CAB화일 제작

테스트용 디지털 서명된 ActiveX 실행할 때 보안 설정

정식 디지털 서명되지 않고 테스트 서명된 ActiveX는 보통 이상으로 보안 설정된 일반 유저의 IE에서는 보안상 실행되지 않는다.

임시 테스트를 하기 위해선 아래와 같은 방법이 있으며 유저들에게 정식으로 배포하기 위해서 공인된 디지털 서명 제공 업체에서 유료로 결제 후에 공인된 디지털 서명을 받아서 배포해야만 한다.

  • 인터넷 옵션의 보안 - 보안 수준 에서 보안 설정을 최하로 변경한다. (서명되지 않은 ActiveX도 다운로드 허용된다.)
  • 인터넷 옵션의 보안 - 신뢰할 수 있는 사이트 - 사이트 에서 해당 사이트를 신뢰하는 사이트로 설정한다.
  • 인터넷 옵션의 보안 - 사용자 지정 수준 - 보안 설정 에서 "서명 안 된 ActiveX 컨트롤 다운로드" "사용 안 함"에서 "확인"으로 변경해야 한다. 일반적으로 기본은 "사용 안 함 (권장)"으로 설정되어 있다.

인증된 디지털 서명 유료 구매하기

디저털 서명은 디지털 서명을 다루는 공인 기관에서 유료로 발급할 수 있다.

  • VeriSign CodeSign : 해외 인증기관. 해외에서 가장 높은 브랜드 : 1년 440000원 / 2년 850000원
  • Thawte CodeSign : 국내에서 가장 많이 사용. 비교적 저렴한 가격 : 1년 180000원 / 2년 320000원
  • Trust CodeSign : 상당히 저렴한 가격 1년 150000원 / 2년 280000원
  • YesSign CodeSign : 금융결제원에서 제공하며 금융관련에서 주로 사용 : 1년 150000원 / 2년 280000원

인증된 디지털 서명 업체

써트 코리아

애니써트

디지털 서명 가이드

자세한 인증서 가이드

4. 웹페이지에 CAB 파일 추가
섹션 편집

ATL 및 MFC 컨트롤은 <OBJECT> 태그를 사용하여 웹 페이지에 포함됩니다. <OBJECT> 태그 안에는 다음과 같은 컨트롤의 세 가지 특성을 지정해야 합니다.

HTML 파일에서 아래와 같이 ActiveX 컨트롤을 끼워 넣는다.

<OBJECT ID="PolyCtl"

CLASSID="CLSID:4CBBC676-507F-11D0-B98B-000000000000"

CODEBASE="http://example.microsoft.com/mydir/polygon.cab">

</OBJECT>

  • ID 컨트롤의 이름
  • CLASSID 컨트롤의 CLSID (위에서 INF 설정시 ActiveX 컨트롤의 CLSID 값과 동일)
  • CODEBASE 컨트롤을 다운로드할 위치. CODEBASE는 다양한 파일 형식을 가리킬 수 있습니다.

CODEBASE는 다음과 같이 OCX 또는 DLL 파일을 직접 지정할 수 있습니다.

CODEBASE="http://example.microsoft.com/mydir/polygon.dll#version=1,0,0,1"

이렇게 하면 DLL 또는 OCX 파일만 다운로드하여 설치하기 때문에 필요한 모든 지원 DLL이 클라이언트 컴퓨터에 있어야 합니다.

CAB 파일에 선택적인 버전 번호를 포함시킬 경우, 해당 버전 번호는 다운로드될 컨트롤을 참조해야 합니다. 예를 들어, POLYGON.DLL의 버전 번호가 1, 0, 0, 1이므로 캐비닛의 버전 역시 1, 0, 0, 1입니다.

CODEBASE="http://example.microsoft.com/mydir/polygon.cab#version=1,0,0,1"

버전 번호를 포함시키지 않을 경우, 동일한 컨트롤의 이전 버전이 클라이언트 컴퓨터에 있어도 새 버전으로 바뀌지 않습니다.

참조 링크:

웹 페이지에 서명된 CAB 파일 포함 (MSDN)

기존 ActiveX 컨트롤 업그레이드 (MSDN)

5. 문제가 생길 경우
섹션 편집

* ActiveX 제작 및 배포 시 참고 및 주의 사항들
- "DestDir은(는) Windows 디렉토리인 경우 10, WindowsSystem(32)인 경우 11이며, Occache 디렉토리인 경우 비워둡니다."

inf 안에 적어주는 배포 되는 파일의 위치입니다.
예)
[test.exe]
file-win32-x86=thiscab
FileVersion=1,0,0,1
DestDir=11

- inf 내에 등록 하려는 ocx 는 [Add.Code] 섹션 맨 위 제일 위에 적어준다.
- 버전 표기 시 쉼표로 꼭 구분해준다. -> 제대로 다운로드 되지 않음
예)
- inf 내 버전 표기 : 2005,4,12,1
- html 페이지 내 : codebase="npos.cab#version=2005,4,21,1"
- 모든 파일이 제대로 다운로드 되었는지 확인해보세요. 가끔 파일이 중간에 다운로드 받다가 다 받지 않은채 손상이 되는 경우가 있더군요.
- 익스플로러 도구-옵션-임시 인터넷 파일-저장된 페이지의 새버전 확인을 페이지를 열 때 마다로 해서 캐쉬 되어 있는 기존 파일을
참조하지 않도록 해주세요.
- 가끔 보니까 downloaded program files 에서 해당 ocx 를 지워도 지워지지 않는 경우가 있는데
regsvr32.exe 로 해제를 해주고 다시 다운로드 받아서 테스트하니 잘 되더군요.

- 그리고 ocx 내부에서 파일을 참조하거나 할 때 예외(파일이 없거나 파일 생성, 삭제 시 예외 발생)가 발생하면 익스플로러가 죽더군요.

- MSDN 에서 본 내용인데 cab 을 묶으실 때 [Add.Code] 내에 놓여져 있는 파일 순서대로 묶어주셔야 한다는겁니다. 아래는 MSDN 원문입니다.

You should run CABARC in the directory that contains your source files (the INF, OCX, and DLL files). The files to be archived in the CAB file should be listed on the command line in the same order they are listed in the INF file. In the example above, the INF file should list NEEDED1.DLL first, then NEEDED2.DLL, and then MYCTL.OCX.

- INF 파일목록에 [Add.Code] 나열된 순서대로 처리를 하지만, 파일들의 설치는 목록의 역순으로 실행된다. 보통 메인 OCX를 파일목록의 첫번째에 두고 참조dll을 그뒤에 두는데, 이것은 메인OCX의 등록시점에 참조dll들의 설치완료를 보장하기위한 것이다.

출처:INF파일

ActiveX 컨트롤이 웹페이지에서 정상적으로 다운로드 안될 경우 로그 보는법 (MSDN)

Code Down Load Log Viewer (cdllogvw.exe) 파일 다운로드

서버 관련 함수중

mswsock.h 안에 WSAID_CONNECTEX 라던가, LPFN_CONNECTEX 같은것이 있습니다.

 

문제는 vs2010에서 이전 vs2005에서 작업한걸 불러오면 여기서 정의되지 않은 심볼이라고 에러 나오더군요.

 

코드 정의창에선 나오는데 왜 그런가 하고 보다가, 위에 보니

 

#if(_WIN32_WINNT >= 0x0501)

 

로 해놨더군요... orz

 

참고로 프로젝트에선 #define _WIN32_WINNT    (0x0500) 로 정의 되었으니...

그 이하 정의된 부분이 다 스킵되어서 컴파일이 안되었던 거였습니다.. ㅠㅠ

 

해결을 위해 위의 0x500 을 0x501로 바꿧습니다.. 

 

 

참고로 MS에선 각 OS마다 사용하는 라이브러리를 구분하기 위해 위의 정의문이 각각 있습니다.

Minimum system required

Macros to define

Windows Server 2003

_WIN32_WINNT>=0x0502

WINVER>=0x0502

Windows XP

_WIN32_WINNT>=0x0501

WINVER>=0x0501

Windows 2000

_WIN32_WINNT>=0x0500

WINVER>=0x0500

Windows NT 4.0

_WIN32_WINNT>=0x0400

WINVER>=0x0400

Windows Me

_WIN32_WINDOWS=0x0500

WINVER>=0x0500

Windows 98

_WIN32_WINDOWS>=0x0410

WINVER>=0x0410

Windows 95

_WIN32_WINDOWS>=0x0400

WINVER>=0x0400

Internet Explorer 6.0

_WIN32_IE>=0x0600

Internet Explorer 5.6

_WIN32_IE>=0x0560

Internet Explorer 5.01, 5.5

_WIN32_IE>=0x0501

Internet Explorer 5.0, 5.0a, 5.0b

_WIN32_IE>=0x0500

Internet Explorer 4.01

_WIN32_IE>=0x0401

Internet Explorer 4.0

_WIN32_IE>=0x0400

Internet Explorer 3.0, 3.01, 3.02

_WIN32_IE>=0x0300

 

OS 이외에 컴파일러에 대한 정의문도 따로 있습니다.

 

MS Visual C++의 컴파일러 자체 매크로 상수


VC++4.0: _MSC_VER = 1000 ( Visual C++ 4.x )
VC++5.0: _MSC_VER = 1100 ( Visual C++ 5 )
VC++6.0: _MSC_VER = 1200 (Visual C++ 6 )
VC++7.0: _MSC_VER = 1300 (Visual C++ .NET )
VC++8.0: _MSC_VER = 1400( Visual C++ .NET 2005 )
VC++9.0: _MSC_VER = 1500( Visual C++ .NET 2008 )

 

정말... 마이그레이션 하나 하는거 힘드네요 ㅠㅠ

이번엔 몇몇 라이브러리에서

 

error C2825: '_Fty': '::'가 뒤에 나오면 클래스 또는 네임스페이스여야 합니다.

이런식으로 뭔가 알지도 못하는 xxresult(28) 파일을 찾아봐염

 

에러가 떨어졌습니다.

 

아무리 이 파일 안을 봐도 뭔가 복잡한 코드라는것 밖에 알 수 없어서

이넘이 컴파일 하다 죽은 소스 부분을 살펴보다가 이런 부분이 나오더군요.

 

error C2678: 이항 '==' : 왼쪽 피연산자로 'std::tr1::_Bind_fty<_Fty,_Ret,_BindN>' 형식을 사용하는 연산자가 없거나 허용되는 변환이 없습니다.
1> with
1> [
1> _Fty=SOCKET,
1> _Ret=std::tr1::_Notforced,
1> _BindN=std::tr1::_Bind2<std::tr1::_Callable_obj<SOCKET,false>,sockaddr *,unsigned int>
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception(470): 'bool std::operator ==(const std::_Exception_ptr &,const std::_Exception_ptr &)'일 수 있습니다.
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception(475): 또는 'bool std::operator ==(std::_Null_type,const std::_Exception_ptr &)'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception(481): 또는 'bool std::operator ==(const std::_Exception_ptr &,std::_Null_type)'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\system_error(408): 또는 'bool std::operator ==(const std::error_code &,const std::error_condition &)'
1> C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\system_error(416): 또는 'bool std::operator ==(const std::error_condition &,const std::error_code &)'
1> C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\include\guiddef.h(192): 또는 'int operator ==(const GUID &,const GUID &)'
1> 인수 목록 '(std::tr1::_Bind_fty<_Fty,_Ret,_BindN>, int)'을(를) 일치시키는 동안
1> with
1> [
1> _Fty=SOCKET,
1> _Ret=std::tr1::_Notforced,
1> _BindN=std::tr1::_Bind2<std::tr1::_Callable_obj<SOCKET,false>,sockaddr *,unsigned int>
1> ]

 

 

이게 뭔말인고 하니

#include <Winsock2.h> 에서 정의된 bind 랑

#include <functional> 에서 정의된 bind가 같은 네임스페이스 상에 있어서 충돌하는거라 하네요..

 

자세한건

  https://connect.microsoft.com/VisualStudio/feedback/details/500364/how-to-avoid-conflicts-between-tr1-bind-and-winsock-bind-function

에 설명하고 있습니다.

 

뭐 어쨋든.. 저걸 해결하기 위해서 stl이 아닌 bind를 쓰고 싶으면 bind -> ::bind로 바꿔서

지금 bind는 소켓 통신용이다 라는걸 알려줘야 한다는군요.....

 

ㅡㅡ.... 헐..... vs2010.....

 

+ Recent posts