게임서버와 웹, 빌링쪽에 연동하려할때 상대쪽에선 자바나 펄위주라 md5에 대한 암호 방식을 선호하던군요.

문제는 이걸 게임서버 (C++)에서 이용하려 할때 마땅한 정보가 없더군요.. ㅠㅠ

그러더중 msdn을 훝어보던중 적당한 예제소스를 발견했습니다.

 

참고 : MD5 ? http://ko.wikipedia.org/wiki/MD5

그리고 전체 알고리즘 : http://www.zedwood.com/article/121/cpp-md5-function

출처 : http://msdn.microsoft.com/ko-kr/library/windows/desktop/aa382380(v=vs.85).aspx

 

.. 좀더 핵심만, MD5 압축데이터를 얻고 오고 싶을때는...

#include <iostream>

#include <windows.h>

#include <wincrypt.h>

 

/*!==========================================================================================

 * @brief     MD5 해쉬 데이터를 얻어오기

 * @return    bool                                           성공/실패

 * @param     char * buffer                                  입력 버퍼

 * @param     DWORD dwBufferSize                             입력 문자열 사이즈 "\0"제외

 * @param     BYTE * byteFinalHash                           결과 해쉬 버퍼

 * @param     DWORD * dwFinalHashSize                        결과 해쉬 버퍼의 크기

 * @author    Kim Dong-Sung (galaxy_wiz@naver.com)

 * @date      2012-11-30

 ==========================================================================================*/

bool GetMD5Hash(char *buffer, DWORD dwBufferSize, BYTE *byteFinalHash, DWORD *dwFinalHashSize)

{

        DWORD          dwStatus       = 0;

        BOOL           bResult        = FALSE;

        HCRYPTPROV     hProv          = 0;

        HCRYPTHASH     hHash          = 0;

        DWORD          cbHashSize     = 0;

 

        try{

               //프로바이더 압축핸들 얻어오기

               if(0 == CryptAcquireContext(&hProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT))

                       throw "CryptAcquireContext";

 

               //압축알고리즘 선택, 여기서는 MD5

               if(0 == CryptCreateHash(hProv, CALG_MD5, 0, 0, &hHash))

                       throw "CryptCreateHash";

 

               //입력된 버퍼를 기반으로 헤쉬 데이터 생성

               if(0 == CryptHashData(hHash, (const BYTE*) buffer, dwBufferSize, 0))

                       throw "CryptHashData";

 

               // 해쉬 사이즈얻어오기

               DWORD dwCount = sizeof(DWORD);

               if(0 == CryptGetHashParam(hHash, HP_HASHSIZE, (BYTE*)&cbHashSize, &dwCount, 0))

                       throw "CryptGetHashParam";

 

               //출력버퍼에 헤쉬데이터를 충분히 담을 있는지 확인

               if(*dwFinalHashSize < cbHashSize){

                       printf("\n Output buffer %d, is not sufficient, Required size = %d", *dwFinalHashSize, cbHashSize);

                       bResult = TRUE;

                       throw "Memory problem";

               }

 

               //이제 해쉬를 계산해서 얻기

               if(CryptGetHashParam(hHash, HP_HASHVAL, byteFinalHash, dwFinalHashSize, 0)){

                       bResult = TRUE;

               }

               else{

                       throw "CryptGetHashParam";

               }

              

        }

        catch(char *errMsg){

               printf("%s failed, Error=0x%.8x\n", errMsg, GetLastError());

        }

 

        if(hHash)      CryptDestroyHash(hHash);

        if(hProv)      CryptReleaseContext(hProv, 0);

 

        return bResult;

}

 

int main(int argc,char *argv[])

{ 

        BYTE byteHashbuffer[256];

        DWORD dwFinalHashSize= 256;

        CHAR str[] = "password";

 

        //_count_of(str)-1을 해서 맨 뒤의 '\0'을 뺀 버퍼 사이즈를 넣음.배열검사 생략했음

        GetMD5Hash(str, _countof(str)-1, byteHashbuffer, &dwFinalHashSize);

 

        printf("%s\n", byteHashbuffer);

        return 0;

} 

 

대충 감을 잡으실수 있을꺼 같습니다.

위의 예제 단어 "password"의 경우 메모리 디버거에서는

 

 

 

같은 결과 값이 나왔습니다.

 

 

boost 관련 예제 프로그래밍..

가끔 경의롭단 생각이.. 이거 만든사람은 뇌에 cpu 박았나...

제 네트워크 프로그래밍에 대해서 복습할 차원(?)으로

게임 회사에서 서버에 이용하는 여러 프로그래밍 기법(?)을 가능한 축약시켜

간단한 채팅서버를 만들었습니다.

 

제작시간 : 약2일 + alpha

사용툴 : Visual Studio 2010, MS-SQL 2012

 

복습 내용 : 네트워크 IOCP, 멀티 쓰레드 기법

                TinyXML 보다 더 짧은 MSXML을 이용한 외부 변수 파싱

                MS-SQL에 연결하기 위한 ADO COM을 사용, DB에 쿼리 던지기

                게임 명령어 처리를 위한 함수포인터 disPatcher

                C#과 이종 교배  (서버는 C++, 클라이언트는 C#)

  

결과 화면 입니다...

 

 

<--- 수정 2012-10-31 --->

역시 주말에 급조해서 만든 소스다 보니 버그가 좀 있었습니다.. orz..

어젯밤 겨우 고쳐서 다시 스크린 샷을 찍었습니다...

 

     ㅁ 버그수정 사항

         - 어느 클라가 /date. /time 같은 명령어로 에코서버 통신을 했다면, 그 이후 다른 클라이언트의 메시지를 1회 못받음.

         - db 주소가 서버와 같지 않으면 db 접속 실패 (ip설정을 잘못 쳤네요 ㅠㅠ)

         - 어떤 클라이언트에서 아무 텍스트도 안넣고 엔터 치면 서버가 다운... (포인터 검사 문제가...)

         - 에러메시지 출력시 한글이 깨지는 문제... orz...

         - 햇갈리는 변수명을 수정... 

 

 

 

 

 

 

서버 프로그램 

 

 

C++11을 많이 이용하려 했으나, auto 키워드 이외 lamda 같은거는 무리하게 넣지 않았습니다.

그래도 auto 때문에 iterator 를 상당히 단축시킬 수 있어서 코딩이 즐겁더군요 ^^

맨위의 DB 쿼리 에러는 멍청하게도 DB마이그레이션을 하지 않아서 생긴 에러 메시지 입니다.. ㅠㅠ

 

 

클라이언트 프로그램

 

사실 C#책에 예제로 있는 소스를 적당히 썻습니다만, 꽤 쓸만했습니다.

서버 만드는데 2일 걸렸지만, 이 클라이언트는 30분정도 끄적이니까 만들어 지네요.

(저 소스가 개행 포함해서 200라인도 안됩니다)

 

일반적으로 메시지를 보내면 접속된 모든 클라이언트에 같은 메시지를 보냅니다.

물론 그 메시지를 보낸 클라이언트를 제외하고 SendAll입니다.

 

별도로 /date, /time 같이 서버의 날짜와 시간은 에코서버퍼럼 해당 명령을 내린 클라에게만 메시지를 보냅니다.

어짜피 시간은 메시지 옆에 찍히는데 뭘 그런걸 만들었냐 하시면.... orz...

온라인 게임에서 중요한 각 패킷의 처리등을 구현하는 방식을 간략화 하다 보니 이렇게 됬습니다..

 

다음 프로젝트는.... 엄청 심플한 mmorpg나 요즘 유행하는 드래곤X라이 같은 서버를.....

 

그리고 다음번엔 서버도 C#으로 작성해 봐야 할거 같습니다.

이 정도의 간편성과 안정성이면, 속도가 조금 느려도 괜찮다는 생각이 드는군요.

 

 Database 쿼리 실행 결과

 

원래 재대로 만들려면, Login 서버 등을 만들어서 이것저것 처리하고 그걸 DB에 넣어야 하지만....

그냥 심플하게 가려고 하다 보니 프로시져를 이용한 쿼리 실행과 결과 보기 정도로 마무리를 했습니다.

 서버 전반적인 복습을 하고 있습니다만...

DB를 붙이려고 하니

 

공급자를 찾을 수 없다는 에러가 나왔습니다.

 

 

평소 회사에는 없던일이라 조금 당황하고 이것저것 삽질했습니다만..

결국위에 노란 형광펜으로 그은 SQLNCLI 가 문제였습니다.

 

이게 MS-SQL 2005, 2008 과 접속할때는 SQLNCLI 이지만,

제 집에 있는 PC에는 MS-SQL2012Express라, 이럴경우에는 SQLNCLI10 으로 지정해야 한다는군요.

 

 

 

.... 음.... orz

 

출처 : http://www.soondesign.co.kr/?p=8331

 

 

Windows Server 2003 서버에 일반 Application을 시작 프로그램에 바로가기로 등록하면 서버가 비정상적으로 리부팅되는 상황과 같이 로그인이 되기 전까지 시작프로그램이 구동되지 않는다는 문제가 발생한다.

이를 해결하기 위해 일반 Application을 서비스로 등록하면 되는데 서비스로 등록된 항목들은 로그온이 되지 않아도 백그라운드로 실행되기 때문에 관리면에서도 효율적이다.

일반 Application을 Windows Server 2003에 Application을 서비스로 등록하는 방법은 아래와 같다.

  1. Windows 2003 Server Resource Kit Tools 다운로드
  2. Windows 2003 Server Resource Kit Tools 설치(C:\Program Files\Windows Resource Kits\Tools)
  3. 설치된 Windows 2003 Server Resource Kit Tools 실행파일을 \Windows\System32 에 복사(같은 이름의 파일들이 있으면 원본 유지)
  4. 시작 – 실행
    INSTSRV prjAttend c:\windows\system32\srvany.exe (서비스에 등록할 이름을 prjAttend라고 할 경우)
    INSTSRV GSAgent c:\windows\system32\srvany.exe (서비스에 등록할 이름을 GSAgent라고 할 경우)
  5. 시작 – 실행 – regedit
    HKLM\System\Current Control Set\Services\prjAttend 에 “Parameters”라는 키 추가
    HKLM\System\Current Control Set\Services\prjAttend\Parameters 에 “Application”이라는 문자열 추가
    HKLM\System\Current Control Set\Services\prjAttend\Parameters\Application 에 실행파일 경로(예, C:\Welfare24\RFID\01.출석관리\prjAttend.exe) 값 추가
  6. 시작 – 제어판 – 관리도구 – 서비스에 생성된 prfAttend의 등록정보 중 로그온탭에 있는 <서비스와 데스크톱 상호작용 허용> 선택상자 체크
  7. 서버 리부팅 후 Application 작동하는지 테스트

+ Recent posts