정리

Visual C++ (2012) 링커 옵션

저장소/VC++

원문 출처 : MSDN magazin (http://technet.microsoft.com/ko-kr/query/y0zzbyt4)



링커 옵션

LINK는 COFF(Common Object File Format) 개체 파일과 라이브러리를 링크하여 실행 파일(.exe)이나 DLL(동적 연결 라이브러리)을 만드는 도구입니다.

다음 표에서는 LINK.exe의 모든 옵션 목록을 보여 줍니다. 이 단원에는 다음 항목에 대한 정보도 포함되어 있습니다.

명령줄에 지정되는 링커 옵션은 대/소문자를 구분하지 않습니다. 즉, /base와 /BASE는 동일하게 취급됩니다.

일부 링커 옵션은 comment pragma를 사용하여 지정할 수 있습니다.

옵션

목적

@

지시 파일을 지정합니다.

/ALIGN

각 섹션의 정렬 방식을 지정합니다.

/ALLOWBIND

DLL을 바인딩할 수 없도록 지정합니다.

/ALLOWISOLATION

매니페스트 조회 동작을 지정합니다.

/ASSEMBLYDEBUG

관리되는 이미지에 DebuggableAttribute를 추가합니다.

/ASSEMBLYLINKRESOURCE

관리되는 리소스에 대한 링크를 만듭니다.

/ASSEMBLYMODULE

MSIL(Microsoft Intermediate Language) 모듈을 어셈블리로 가져오도록 지정합니다.

/ASSEMBLYRESOURCE

관리되는 리소스 파일을 어셈블리에 포함시킵니다.

/BASE

프로그램의 기준 주소를 설정합니다.

/CLRIMAGETYPE

CLR 이미지의 형식(IJW, pure 또는 safe)을 설정합니다.

/CLRSUPPORTLASTERROR

P/Invoke 메커니즘을 통해 호출한 함수의 마지막 오류 코드를 저장합니다.

/CLRTHREADATTRIBUTE

CLR 프로그램의 진입점에 적용하려는 스레드 특성을 지정합니다.

/CLRUNMANAGEDCODECHECK

/CLRUNMANAGEDCODECHECK는 링커가 생성하여 관리 코드에서 네이티브 DLL로 호출되는 PInvoke 스텁에 링커가 SuppressUnmanagedCodeSecurity 특성을 적용할지 여부를 지정합니다.

/DEBUG

디버깅 정보를 만듭니다.

/DEF

모듈 정의 파일(.def)을 링커에 전달합니다.

/DEFAULTLIB

외부 참조를 확인할 때 지정된 라이브러리를 검색합니다.

/DELAY

DLL의 지연 로드를 제어합니다.

/DELAYLOAD

지정된 DLL을 지연 로드시킵니다.

/DELAYSIGN

어셈블리에 부분적으로 서명합니다.

/DLL

DLL을 빌드합니다.

/DRIVER

Windows NT 커널 모드 드라이버를 만듭니다.

/DYNAMICBASE

로드할 때 Windows Vist의 ASLR(Address Space Layout Randomization) 기능을 사용하여 임의로 기준 주소를 지정할 수 있는 실행 가능 이미지를 생성할지 여부를 지정합니다.

/ENTRY

시작 주소를 설정합니다.

/errorReport

내부 링커 오류를 Microsoft에 보고합니다.

/EXPORT

함수를 내보냅니다.

/FIXED

기본 기준 주소에서만 로드할 수 있는 프로그램을 만듭니다.

/FORCE

확인되지 않거나 기호가 두 번 이상 정의된 경우에도 링크를 완료하도록 합니다.

/FUNCTIONPADMIN

핫 패치할 수 있는 이미지를 만듭니다.

/HEAP

힙 크기를 바이트 단위로 설정합니다.

/IDLOUT

.idl 파일과 기타 MIDL 출력 파일의 이름을 지정합니다.

/IGNOREIDL

특성 정보가 .idl 파일로 처리되지 않도록 합니다.

/IMPLIB

기본 가져오기 라이브러리 이름을 무시합니다.

/INCLUDE

기호 참조를 강제 적용합니다.

/INCREMENTAL

증분 링크를 제어합니다.

/KEYCONTAINER

어셈블리에 서명할 키 컨테이너를 지정합니다.

/KEYFILE

어셈블리에 서명할 키 또는 키 쌍을 지정합니다.

/LARGEADDRESSAWARE

응용 프로그램에서 2GB 이상의 주소를 지원하도록 컴파일러에 지시합니다.

/LIBPATH

사용자가 환경 라이브러리 경로를 재정의할 수 있도록 합니다.

/LTCG

링크 시간 코드 생성을 지정합니다.

/MACHINE

대상 플랫폼을 지정합니다.

/MANIFEST

side-by-side 매니페스트 파일을 만듭니다.

/MANIFESTDEPENDENCY

매니페스트 파일에 <dependentAssembly> 섹션을 지정합니다.

/MANIFESTFILE(매니페스트 파일 이름 지정)

매니페스트 파일의 기본 이름을 변경합니다.

/MANIFESTUAC

프로그램 매니페스트에 UAC(사용자 계정 컨트롤) 정보를 포함할지 여부를 지정합니다.

/MAP

맵 파일을 만듭니다.

/MAPINFO

지정한 정보를 맵 파일에 포함시킵니다.

/MERGE

섹션을 결합합니다.

/MIDL

MIDL 명령줄 옵션을 지정합니다.

/NOASSEMBLY

.NET Framework 어셈블리를 만들지 않습니다.

/NODEFAULTLIB

외부 참조를 확인할 때 모든 또는 지정한 기본 라이브러리를 무시합니다.

/NOENTRY

리소스 전용 DLL을 만듭니다.

/NOLOGO

시작 배너를 표시하지 않습니다.

/NXCOMPAT

실행 파일을 Windows 데이터 실행 방지 기능과 호환되는지 테스트한 것으로 표시합니다.

/OPT

LINK 최적화를 제어합니다.

/ORDER

COMDAT을 미리 결정된 순서로 이미지에 배치합니다.

/OUT

출력 파일 이름을 지정합니다.

/PDB

PDB(프로그램 데이터베이스) 파일을 만듭니다.

/PDBALTPATH

대체 위치를 사용하여 PDB 파일을 저장합니다.

/PDBSTRIPPED

전용 기호가 없는 PDB(프로그램 데이터베이스) 파일을 만듭니다.

/PGD

프로필 기반 최적화를 위한 .pgd 파일을 지정합니다.

/PROFILE

성능 도구 프로파일러와 함께 사용할 수 있는 출력 파일을 생성합니다.

/RELEASE

.exe 헤더의 체크섬을 설정합니다.

/SAFESEH

이미지에 안전한 예외 처리기 테이블이 포함되도록 지정합니다.

/SECTION

섹션의 특성을 재정의합니다.

/STACK

스택 크기를 바이트 단위로 설정합니다.

/STUB

MS-DOS 스텁 프로그램을 Win32 프로그램에 연결합니다.

/SUBSYSTEM

운영 체제에 .exe 파일의 실행 방법을 지정합니다.

/SWAPRUN

운영 체제에서 링커 출력을 실행하기 전에 스왑 파일로 복사하도록 지정합니다.

/TLBID

링커에서 생성한 형식 라이브러리의 리소스 ID를 지정할 수 있도록 합니다.

/TLBOUT

.tlb 파일과 기타 MIDL 출력 파일의 이름을 지정합니다.

/TSAWARE

터미널 서버에서 실행하도록 디자인된 응용 프로그램을 만듭니다.

/VERBOSE

링커 진행 메시지를 표시합니다.

/VERSION

버전 번호를 할당합니다.

/WX

링커 경고를 오류로 처리합니다.

자세한 내용은 컴파일러 제어 LINK 옵션을 참조하십시오.


error LNK2005 - uafxcw.lib, LIBCMT.lib

저장소/VC++


다음과 같은 문제가 발생.


1>uafxcw.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z)이(가) LIBCMT.lib(new.obj)에 이미 정의되어 있습니다.

1>uafxcw.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z)이(가) LIBCMT.lib(delete.obj)에 이미 정의되어 있습니다.


C Runtime Library와 MFC Library의 import 순서에 의한 링크시 오류라고 한다.

일단 해결 방법은 다음과 같이 하여 import 순서를 변경해주면 되겠다.


프로젝트 속성 -> 링커 -> 입력 -> 특정 기본 라이브러리 무시 : uafxcwd.lib; libcmtd.lib

프로젝트 속성 -> 링커 -> 입력 -> 추가 종속성 : uafxcwd.lib; libcmtd.lib


링크 옵션 /verbose:lib 를 통해 설정 전후의 Library Import 순서를 확인할 수 있다.

설정 전
1>  라이브러리를 검색하고 있습니다.
1>      C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\lib\LIBCMTD.lib 검색 중:
1>      C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\lib\OLDNAMES.lib 검색 중:
1>      C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\atlmfc\lib\uafxcwd.lib 검색 중:
1>uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z)이(가) LIBCMTD.lib(new.obj)에 이미 정의되어 있습니다.
1>uafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z)이(가) LIBCMTD.lib(dbgdel.obj)에 이미 정의되어 있습니다.
1>      C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\kernel32.lib 검색 중:
...

설정 후
1>  라이브러리를 검색하고 있습니다.
1>      C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\atlmfc\lib\uafxcwd.lib 검색 중:
1>      C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\lib\libcmtd.lib 검색 중:
1>      C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\lib\OLDNAMES.lib 검색 중:
1>      C:\Program Files (x86)\Windows Kits\8.0\lib\win8\um\x86\kernel32.lib 검색 중:


그러하다!


[펌] 링크시 나는 에러 추적 하기

저장소/VC++

원문 출처 : 샤방샤방님 블로그(http://blog.naver.com/drvoss/20064150564)



짜증나는 워닝과 에러 중에헤더파일 순서에 따라 발생하는 워닝/에러가 있습니다특히 링크타임에 나는 에러는 네이밍 모양새가 재밌게 생겨먹지 않은 스타일로 생기는 데다가 링커가 별로 힌트를 주지 않아서 짜증이 나기도 합니다예를 들면 아래와 같은 겁니다.

 

1>Generating Code...

1>Compiling resources...

1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1

1>Copyright (C) Microsoft Corporation.  All rights reserved.

1>Compiling manifest to resources...

1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1

1>Copyright (C) Microsoft Corporation.  All rights reserved.

1>Linking...

1>uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMTD.lib(new.obj)

1>uafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMTD.lib(dbgdel.obj)

 

위 예는 MFC프로젝트에서 모든 파일에서 MFC 헤더를 다른 헤더 보다 먼저 선언해야 하는데(대부분 stdafx.h를 가장 상위에 선언합니다.),  MFC 프로젝트에서 사용하던 파일을 Import 하고 컴파일 하는 순간 발생했습니다.

 

이런 에러의 경우 대처법은 의외로 간단 합니다일단 똑똑고 기억력 좋으신 분들은 자기가 했던 행위들의 콜스택을 하나하나 거슬러 올라가시면서 대처 하는법이 있고이게 가장 비용대비 시간단축 효가가 가장 좋습니다.

 

순간 욱해서 콜스택 거슬러 올라가기 힘드신 (저 같은;;)분들은 아래처럼 대처 하시면 됩니다먼저 링커 옵션에 아래 옵션을 추가 합니다.

 

/verbose:lib

 

 

그리고 다시 빌드 하면 링킹타임에 library를 스캔하는 리스트가 아래와 같이 output창에 나오게 됩니다.

 

1>Generating Code...

1>Compiling resources...

1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1

1>Copyright (C) Microsoft Corporation.  All rights reserved.

1>Compiling manifest to resources...

1>Microsoft (R) Windows (R) Resource Compiler Version 6.1.6723.1

1>Copyright (C) Microsoft Corporation.  All rights reserved.

1>Linking...

1>Searching libraries

1>    Searching C:\Program Files\Microsoft Visual Studio 9.0\VC\lib\DelayImp.lib:

1>    Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\uuid.lib:

1>    Searching C:\Program Files\Microsoft Visual Studio 9.0\VC\lib\LIBCMTD.lib:

1>    Searching C:\Program Files\Microsoft Visual Studio 9.0\VC\lib\OLDNAMES.lib:

1>    Searching C:\Program Files\Microsoft Visual Studio 9.0\VC\atlmfc\lib\uafxcwd.lib:

1>uafxcwd.lib(afxmem.obj) : error LNK2005: "void * __cdecl operator new(unsigned int)" (??2@YAPAXI@Z) already defined in LIBCMTD.lib(new.obj)

1>uafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCMTD.lib(dbgdel.obj)

1>    Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\kernel32.lib:

1>    Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\user32.lib:

1>    Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\gdi32.lib:

1>    Searching C:\Program Files\Microsoft SDKs\Windows\v6.0A\\lib\uuid.lib:

 

윗 예에서 uafxcwd.lib를 링크 할 때링크에러가 났고에러를 유발한 유력한 용의자는 uuid.lib입니다왜냐면계속 다른 애들은 디폴트 경로에서 링크되는데 uuid.lib만 sdk 에서 링크 되었고, MFC에서 new를 재정의 하기 때문에이전에 new가 정의되어 있는 파일이 링크되면 안됩니다여기서 “stdafx.h”파일을 추가 하는 것을 잊었구나 하는 생각이 듭니다.

 

/verbose 옵션을 써보지 않으신 분들은 한번 넣고 컴파일을 해보시면 쓰잘떼기 없는 정보까지 주르륵 나와서 놀라실 껍니다. 여러가지 링킹 타임에 하는 작업 정보를 자세히 알려주는 것을 알 수 있습니다. 윗예의 :lib처럼 뒷부분에 세부 옵션을 붙여 보기 좋게 정보를 추출하는 작업이 익숙해 지면 일반적인 컴파일시 정보를 잘 제공해주지 않는 링킹 타임시 발생하는 에러에 정보를 얻어 디버깅 작업 시간을 단축 시킬 수 있습니다.


CDHtmlDialog, CHtmlView에서 IE 엔진 버전 고르기

저장소/VC++

관련 링크들

http://msdn.microsoft.com/en-us/library/ee330730%28VS.85%29.aspx#browser_emulation

http://www.codewrecks.com/blog/index.php/2011/06/06/witch-version-of-browser-is-used-by-the-webbrowser-control/

http://blogs.msdn.com/b/ie/archive/2008/03/18/webbrowser-control-rendering-modes-in-ie8.aspx

http://blogs.msdn.com/b/ie/archive/2009/03/10/more-ie8-extensibility-improvements.aspx



정리하기 귀찮아서 퍼온 내용은 아래에 ㅜㅜ


원문 출처 : http://codemuri.tistory.com/752




IE8, 9 가 출시되었음에도 불구하고 CHtmlView 와 CDHtmlDialog 의 MSHTML 엔진 버전은 6 또는 7 버전을 사용합니다. MSDN 에는 호환성의 이유로  디폴트로 IE7 Standards Mode 로 실행된다고 명시하고 있습니다.

다음 방법을 이용하여 MSHTML 엔진의 버전을 IE8 또는 IE9 로 명시할 수 있습니다.

HTML 문서에 지정하는 방법

아래처럼 html 에 meta 태그를 선언하면 됩니다.

1
2
3
4
<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="X-UA-Compatible" content="IE=9" >


레지스트리를 이용하는 방법

IE8 Standards Mode 로 실행하는 방법 (IE9 는 9000 입니다)

[(HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE)\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION]
"MyApplication.exe" = dword 8000 (Hex: 0x1F40)


IE7 Standards Mode 로 실행하는 방법

[(HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE)\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION]
"MyApplication.exe" = dword 7000 (Hex: 0x1B58)


IE8 Standards Mode 로 강제하는 방법

[(HKEY_CURRENT_USER or HKEY_LOCAL_MACHINE)\Software\Microsoft\Internet Explorer\Main\FeatureControl\FEATURE_BROWSER_EMULATION]
"MyApplication.exe" = dword 8888 (Hex: 0x22B8)

4K, 64K, 1MB, 1GB, 2GB의 DWORD 표현

저장소/VC++

원문 출처 : http://callibri.egloos.com/2674940


4K                      0x00001000

64K                   0x00010000

 

1MB                  0x00100000

 

1GB                   0x40000000

2GB                   0x80000000


예를 들어, 0x0000bad4라는 값이 win32의 no-access region 중 하나인 0~64K 영역(정확히는 0x00000000~0x0000ffff)에 속하는가 아닌가를 금방 알려면 위 표현을 외워 놓는.

GetQueuedCompletionStatus의 0 transferred bytes (5)

저장소/VC++

출처 : http://blog.naver.com/winjks/10014283819


걍 참고해서 보자.

client연결 상태를 getpeername를 사용해서 확인해보는 것도 나쁘지 않을듯.


손님





올리기IOCP를 사용한 소켓에서의 클라이언트 소켓의 종료 감지...올려짐: 2004-07-05 23:36
인용과 함께 답변 이 게시물을 del.icio.us에 추가

안녕하세요... 눈팅만 하다 궁금한 사항이 있어 자문을 구합니다. 

iocp를 사용해 접속된 클라이언트의 종료를 인지하는 부분에서 접속이 종료된 클라이언트를 
100% 감지 할수 있는 방법이 있는지 궁금합니다. 

지금 사용하는 방법은 접속된 모든 클라이언트는 항상 ReadFile로 읽기 대기 상태로 만들어 놓고, 
필요시 WriteFile을 호출하고 있으며, 워커쓰레드를 몇개 만들어 GetQueuedCompletionStatus 호출에서 리턴되는 값으로 접속 종료를 판단하고 있습니다. 
그런데..... 간혹 클라이언트가 접속이 종료 되었는데 iocp에서 감지가 되지 않는 경우가 있습니다. 
컴퓨터 사양이 낮은경우 접속 끊김을 감지 하지 못하는경우가 더 많은듯 하구요. 

이전 iocp를 사용하지 않을경우에는 클라이언트 소켓마다 송수신시 시간을 저장해 일정 시간동안 통신이 이루어지지 않은 소켓의 경우 살아있는지 패킷을 전송시켜서 사용했었는데...진정 iocp에서도 이방법을 사용해야 하나요 ? 아니면 제가 iocp를 잘못 사용하고 있는건가요? 

여러분들은 어떤 방법을 사용하고 계신지 의견 듣고 싶습니다.
위로
 
symlink



가입: 2004년 6월 1일
올린 글: 31

올리기Re: IOCP를 사용한 소켓에서의 클라이언트 소켓의 종료 감지...올려짐: 2004-07-06 09:00
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
안녕하세요... 눈팅만 하다 궁금한 사항이 있어 자문을 구합니다. 

iocp를 사용해 접속된 클라이언트의 종료를 인지하는 부분에서 접속이 종료된 클라이언트를 
100% 감지 할수 있는 방법이 있는지 궁금합니다. 

지금 사용하는 방법은 접속된 모든 클라이언트는 항상 ReadFile로 읽기 대기 상태로 만들어 놓고, 
필요시 WriteFile을 호출하고 있으며, 워커쓰레드를 몇개 만들어 GetQueuedCompletionStatus 호출에서 리턴되는 값으로 접속 종료를 판단하고 있습니다. 
그런데..... 간혹 클라이언트가 접속이 종료 되었는데 iocp에서 감지가 되지 않는 경우가 있습니다. 
컴퓨터 사양이 낮은경우 접속 끊김을 감지 하지 못하는경우가 더 많은듯 하구요. 

이전 iocp를 사용하지 않을경우에는 클라이언트 소켓마다 송수신시 시간을 저장해 일정 시간동안 통신이 이루어지지 않은 소켓의 경우 살아있는지 패킷을 전송시켜서 사용했었는데...진정 iocp에서도 이방법을 사용해야 하나요 ? 아니면 제가 iocp를 잘못 사용하고 있는건가요? 

여러분들은 어떤 방법을 사용하고 계신지 의견 듣고 싶습니다.


GetQueuedCompletionStatus에서 반환되는 값이 FALSE일때만 처리하신듯.. 

처리가 완료되었더라도 처리된 데이터 크기가 0 이면 접속이 끊긴 상태입니다. 

대부분, 0바이트 짜리 데이터를 보내지 않는 다는 가정하게 내부에서 소켓의 끊긴 문제를 이런식으로 

반환하기도 합니다. 이런 식으로해서 다음과 같이 처리할수도 있습니다. (IOCP가 아닌 경우에) 

ioctlsocket( sock, FIONREAD, &nbytes) 

에서 nbytes 가 0인 경우도 소켓이 끊긴 상태입니다. 

참, UDP인 경우 0바이트가 발생된다고 소켓을 끊으면 안되겠죠^^; 

그럼..
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
sphawk



가입: 2004년 5월 28일
올린 글: 95
소속: Come back to Univ.

올리기접속 끊김.올려짐: 2004-07-06 10:16
인용과 함께 답변 이 게시물을 del.icio.us에 추가

랜선을 뽑는다던가. 갑자기 컴터가 재부팅이 되었다던가 하는 경우는 접속 끊어짐 감지가 안 될 수도 있습니다. 
전에 redwiki에서, ACE관련 글을 봤었는데, ACE도 저런 경우에는 ping check를 쓰라고 하더군요. 
(지금 찾으려니 wiki가 많이 개편되어서 찾을 수가 없더군요.) 

제 경험상으로도. 무슨 짓을 해도 ping check를 쓰지 않고, 접속 끊어짐 감지를 완벽하게 할 수는 없었습니다. 
.... 저거 때문에 피 본 일이 있기도 한데. 맨정신으로는 못할 말이고.. 

ps. ping check라는게. 다들 아시겠지만서도..(이동네는 운만 띄워도 아.. 그거.. 하는 동네라.) 
icmp ping을 쓰는 게 아니라.. 그냥 클라이언트가 작은 패킷 보내서.. 나 살아 있소 정도만 보내는.. 
서버는 받아서 다시 되돌려 보내고.. 양쪽 다, 일정 시간 동안 응답이 없으면 즐.. 시키는...
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
miracle2k



가입: 2003년 7월 9일
올린 글: 3

올리기Re: IOCP를 사용한 소켓에서의 클라이언트 소켓의 종료 감지...올려짐: 2004-07-06 10:37
인용과 함께 답변 이 게시물을 del.icio.us에 추가

symlink 씀:

GetQueuedCompletionStatus에서 반환되는 값이 FALSE일때만 처리하신듯.. 
처리가 완료되었더라도 처리된 데이터 크기가 0 이면 접속이 끊긴 상태입니다. 


의견 감사합니다 ^^ 
현재 저의 쓰레드 루프에서 처리하는 방법을 대충 적어 보면... 

loop 

if ( FALSE == GetQueuedCompletionStatus ) { 
if ( NULL != lpOverlapped ) { 
소켓 종료 처리... 
} else { 
쓰레드 종료.... 

} else { 
if ( 0 == dwBytesIO ) { 
소켓 종료 처리... 
} else 
if ( -1 == dwBytesID ) { 
쓰레드 종료... 
} else { 
정상처리.... 




위와 같이 되어 있고 지적해 주신 0 == dwBytesIO 부분은 처리를 하고 있습니다. 
symlink님 께서는 HearBeats(ping-pong )패킷을 클라이언트에 전송하지 않으시고도 iocp에서 발생하는 이벤트 만으로 모든 클라이언트가 관리되시는 건가요? m$에서 제공하는 iocp예제를 봐도 
소켓을 닫는 부분은 위의 부분과 Read,Write시 Pending오류를 제외한 오류에서 닫는것만 보이네요... 
별도로 클라이언트 소켓에 체크 패킷을 날려야 되는 방법만 있는지... 

기분학상.... 모든 클라이언트 소켓을 iocp에 등록하고 ReadFile시켜 놨으면... 클라이언트 종료시 읽기 오류가 발생하여 iocp에서 통보를 해줘야 될거 같은데,,,, iocp한테 무시당하고 있는 상황입니다... m$넘들이 물먹이는건지...
위로
사용자 정보 보기 쪽지 보내기 
miracle2k



가입: 2003년 7월 9일
올린 글: 3

올리기올려짐: 2004-07-06 10:46
인용과 함께 답변 이 게시물을 del.icio.us에 추가

앗... sphawk 님께서 글을 작성하는 도중에 답변을 ^^... 
저도 최후의 방법을 생각중인데... iocp가 그래도 뭔가를 해주지 않을까 하는 기대를 아직 버리지 못하고 있습니다...^^;
위로
사용자 정보 보기 쪽지 보내기 
일지매



가입: 2003년 11월 3일
올린 글: 40

올리기올려짐: 2004-07-06 10:53
인용과 함께 답변 이 게시물을 del.icio.us에 추가

포기하세요. 안해줍니다. 이건 iocp문제가 아니라 WAN의 문제죠.
_________________
정의구현!!
위로
사용자 정보 보기 쪽지 보내기 
symlink



가입: 2004년 6월 1일
올린 글: 31

올리기Re: 접속 끊김.올려짐: 2004-07-06 11:08
인용과 함께 답변 이 게시물을 del.icio.us에 추가

sphawk 씀:
랜선을 뽑는다던가. 갑자기 컴터가 재부팅이 되었다던가 하는 경우는 접속 끊어짐 감지가 안 될 수도 있습니다. 
전에 redwiki에서, ACE관련 글을 봤었는데, ACE도 저런 경우에는 ping check를 쓰라고 하더군요. 
(지금 찾으려니 wiki가 많이 개편되어서 찾을 수가 없더군요.) 

제 경험상으로도. 무슨 짓을 해도 ping check를 쓰지 않고, 접속 끊어짐 감지를 완벽하게 할 수는 없었습니다. 
.... 저거 때문에 피 본 일이 있기도 한데. 맨정신으로는 못할 말이고.. 

ps. ping check라는게. 다들 아시겠지만서도..(이동네는 운만 띄워도 아.. 그거.. 하는 동네라.) 
icmp ping을 쓰는 게 아니라.. 그냥 클라이언트가 작은 패킷 보내서.. 나 살아 있소 정도만 보내는.. 
서버는 받아서 다시 되돌려 보내고.. 양쪽 다, 일정 시간 동안 응답이 없으면 즐.. 시키는...


저 같은 경우는 님이 말씀하신 방식의 경우 불필요한 패킷을 보내야 되기 때문에.. 잘 사용하지는 않고 
다른 방법을 사용합니다. 

제가 리눅스에서 주로 개발해서 일단 리눅스 기준으로 말씀드리겠습니다. 

전제 조건: 접속된 소켓은 항상 데이터를 전송한다고 보고요.. 

처리: 
1. 최종 데이터 발생시간으로 부터 n 이상 데이터 발생이 없다면 소켓은 일단 차단(close) 
2. 전송중에 EAGAIN이 발생되는 경우 소켓 차단(close) 
: EAGAIN의 경우 상대방이 데이터를 받을수 없거나, 상대방이 소켓 버퍼에 데이터를 넣을수 없을때 
발생되는 오류 입니다. 
3. 데이터를 받을때, getpeername을 통해 소켓의 상태를 한번더 검사합니다. 
: 이경우는 중간에 소켓이 강제적으로 닫힌 경우나 내부에서 소켓을 폐쇄했는지 검사할때 사용합니다. 

그럼.
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
mastercho



가입: 2004년 5월 9일
올린 글: 213

올리기올려짐: 2004-07-06 11:42
인용과 함께 답변 이 게시물을 del.icio.us에 추가

예를 들면 
서버가 클라이언트의 메시지를 받아서 IOCP에서 리턴되어 메세지에 관한 작업을 처리하고 있습니다 

그런데 일이 끝나기도전에 
클라이언트에서 갑자기 접속을 끊어버리는 경우가 있을수 있는데 [connect reset 경우] 

그럴 경우 서버에서 전에 보낸 클라이언트 메세지 작업이 끝난후, 다시 iocp Request 요청을 하는 루틴에서 
io 요청 실패를 하게 됩니다 

따라서 IOCP 대기할때 0값을 리턴 받지 못하게 됩니다 

그래서 이런 인식하지 못하는 현상이 많이 발생하는것으로 보입니다
위로
사용자 정보 보기 쪽지 보내기 이메일 보내기 
비회원
손님





올리기올려짐: 2004-07-06 11:59
인용과 함께 답변 이 게시물을 del.icio.us에 추가

mastercho 씀:
예를 들면 서버가 클라이언트의 메시지를 받아서 IOCP에서 리턴되어 메세지에 관한 작업을 처리하고 있습니다 그런데 일이 끝나기도전에 클라이언트에서 갑자기 접속을 끊어버리는 경우가 있을수 있는데 [connect reset 경우] 그럴 경우 서버에서 전에 보낸 클라이언트 메세지 작업이 끝난후, 다시 iocp Request 요청을 하는 루틴에서 io 요청 실패를 하게 됩니다 따라서 IOCP 대기할때 0값을 리턴 받지 못하게 됩니다 그래서 이런 인식하지 못하는 현상이 많이 발생하는것으로 보입니다


역시 IOCP 문제가 아니고 구조적 결함을 가진 프로그램 문제입니다. IOCP의 worker 쓰레드에서 메시지에 관련된 작업을 직접하는건 대단히 좋지 않은 방법입니다. 쓰레드의 메시지 처리 시간이 길어지면 io 처리 효율이 낮아지게 되고 그 문제를 해결하기 위해서 worker 쓰레드가 많아지는 악순환을 초래하게 됩니다. 

그리고 IOCP는 커널 레벨의 Queue입니다.iocp request를 요청하는 루틴에서 io 요청 실패를 하게 된다는 말이 무슨 말인지 도저히 해석을 할수가 없네요.
위로
 
miracle2k



가입: 2003년 7월 9일
올린 글: 3

올리기올려짐: 2004-07-06 12:07
인용과 함께 답변 이 게시물을 del.icio.us에 추가

mastercho 님의 글에 궁금한것이 하나더 생겼네요 ^^; 

'iocp에 read시 소켓이 끊겨 있으면 iocp가 false를 리턴하지만 이미 read가 되어 대기중인 상태에서 소켓이 끊기면 iocp가 통보를 해주지 않는다' 라고 한다면... ReadFile, WriteFile시에 리턴되는 오류값으로 이미 소켓의 오류가 판단이 되고, 이때는 iocp에 등록이 되지 않을것이며,,, GetQueuedCompletionStatus 에서 false나 0 == dwBytesIO 되는 경우는 이미 Read,Write가 등록되어 대기중일때 리턴하는 값이 아닌가요? 
이렇게 본다면 iocp에서 대기중일때도 0이나 0 == dwBytesIO를 리턴한다고 봐야 될것 같은데.... 어떠신지...
위로
사용자 정보 보기 쪽지 보내기 
raonhaje



가입: 2004년 6월 22일
올린 글: 32
소속: 마이에트 엔터테인먼트

올리기올려짐: 2004-07-06 14:45
인용과 함께 답변 이 게시물을 del.icio.us에 추가

저역시 클라이언트 뻗음등으로 끊길때 서버에 남는 문제를 겪고있습니다. 
현재 해결방안은 어느기간동안 통신 없던 클라이언트들에게 패킷하나 보내보면 보내기 실패가 되면서 끊김처리를 할수 있더군요. 
약간 맘에 안들긴하지만 여튼 뾰족한 방법이 안보이네요.
위로
사용자 정보 보기 쪽지 보내기 글 올린이의 웹사이트 방문 
sphawk



가입: 2004년 5월 28일
올린 글: 95
소속: Come back to Univ.

올리기sparrowhawk올려짐: 2004-07-06 14:49
인용과 함께 답변 이 게시물을 del.icio.us에 추가

mastercho 씀:
예를 들면 
서버가 클라이언트의 메시지를 받아서 IOCP에서 리턴되어 메세지에 관한 작업을 처리하고 있습니다 

그런데 일이 끝나기도전에 
클라이언트에서 갑자기 접속을 끊어버리는 경우가 있을수 있는데 [connect reset 경우] 

그럴 경우 서버에서 전에 보낸 클라이언트 메세지 작업이 끝난후, 다시 iocp Request 요청을 하는 루틴에서 
io 요청 실패를 하게 됩니다 

따라서 IOCP 대기할때 0값을 리턴 받지 못하게 됩니다 

그래서 이런 인식하지 못하는 현상이 많이 발생하는것으로 보입니다


... 저같은 경우에는, iocp Request ( WSASend나 WSARecv 이겠군요. ) 에서 실패하면 소켓 닫게 짰습니다. 
소켓 닫혀 있으면 나중에 연결 셋에서 제거하고.. 
만일 끊김 인식 못하는 부분이 저거뿐이였다면 얼마나 좋았겠습니까 T_T;; 

참고로.. io pending 이 성공하면 ( WSASend, WSARecv등이 성공하거나 
WSA_IO_PENDING 이외의 에러를 뱉지 않으면.. ) 
작업이 실패하더라도, 반드시 GetQueuedCompletionStatus에 옵니다. 
MSDN에서 확실히 온다고 했으니 오겠지요 ;;; 

... 그런데 그 비정상 접속 끊김은 WSARecv 걸어놓은게 하염없이 기다려도 오지를 않지요;; 
나중에 소켓 끊으면 그때서야 '작업 실패여~' 하고 오니.. 

아마도 hardly closure를 한다던가, 랜선이 뽑힌다던가 하면서 FIN이 날아가서 그런 거 같기도 하고. 
에구구. 나중에 TCP/IP 프로토콜이나 좀더 공부 좀 해야겠군요. 그럼 말빨이 달려서 이만..
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
Testors



가입: 2003년 7월 26일
올린 글: 451
소속: (주)nFlavor

올리기올려짐: 2004-07-07 01:10
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
역시 IOCP 문제가 아니고 구조적 결함을 가진 프로그램 문제입니다. IOCP의 worker 쓰레드에서 메시지에 관련된 작업을 직접하는건 대단히 좋지 않은 방법입니다. 쓰레드의 메시지 처리 시간이 길어지면 io 처리 효율이 낮아지게 되고 그 문제를 해결하기 위해서 worker 쓰레드가 많아지는 악순환을 초래하게 됩니다.


어짜피 메시지 처리를 못할거라면 IO 에서 recv 한다해도 소용 없을듯 한데요? 
처리속도가 recv 속도를 못따라가 준다면 버퍼에 쌓이기만 할텐데요.. 
쌓아놓고 처리를 못하느니 받지 않는게 나을듯 합니다. 

그리고 제 생각으로는 IOCP의 worker 쓰레드에서 메시지에 관련된 작업을 직접 하지 않는것은 IOCP 를 제대로 쓰는 방법(쓰레드 풀링을 통한 SMP 활용)이 아닌듯 합니다..
위로
사용자 정보 보기 쪽지 보내기 이메일 보내기 글 올린이의 웹사이트 방문 MSN 메신저 
ICQ 번호
비회원
손님





올리기Re: sparrowhawk올려짐: 2004-07-07 10:22
인용과 함께 답변 이 게시물을 del.icio.us에 추가

sphawk 씀:

아마도 hardly closure를 한다던가, 랜선이 뽑힌다던가 하면서 FIN이 날아가서 그런 거 같기도 하고. 
에구구. 나중에 TCP/IP 프로토콜이나 좀더 공부 좀 해야겠군요. 그럼 말빨이 달려서 이만..


랜선이 뽑히든가 하는 문제로 네트웍 인식 못하는 문제는 TCP/IP의 문제이지 IOCP의 문제가 아닙니다 

따라서 TCP/IP 소켓를 사용하는 모든 서버는 그런 종류의 연결이 끊였는지 감지 하지 못합니다
위로
 
비회원
손님





올리기결국 IOCP 비정상 처리는 어떻게...?올려짐: 2006-09-12 16:46
인용과 함께 답변 이 게시물을 del.icio.us에 추가

이 쓰레드를 쓰신분은 결론을 어케 내셨는지 궁금하네요. 

역시 비정상 종료 처리로 지금 머리를 굴리고 있는중입니다만, Alive Ping 이외에 다른 방법이 없는것 

같기도 하고.. 


결국은 현재 접속하고 있는 connection들에 대해 주기적으로 Pint Time Check를 해야 하는 것일까요. 

모든 connection에 대한 주기적 검사란게 이벤트 방식의 IOCP의 구조에 안맞는것 같은데, 

좀 우아한 방법이 없을까 고민이 됩니다. 


고민하다가 SIO_KEEPALIVE_VALS 라는 소켓 옵션을 사용해볼까 해서 테스트 해봤는데 

무언가 잘못됐는지 제대로 동작을 안하네요. 

열린 connection에 SIO_KEEPALIVE_VALS 5초 옵션을 주고 연결된 클라이언트의 랜선을 확~ 

뽑았는데, 5분이 지나도 감지 못합니다. -0-;;;; 


혹시 이것을 IOCP에서 테스트 해보시거나 사용해 보신분도 의견을 주시면 감사하겠습니다.
위로
 
비회원
손님





올리기Alive Ping만이 확실한 방법일듯..올려짐: 2006-09-19 12:15
인용과 함께 답변 이 게시물을 del.icio.us에 추가

다만...효율적인 Heartbeat 전송 방법을 생각해야겠죠. 

제경우는... 

클라이언트에서 패킷전송할때 매번 비트타임을 현재시간으로 초기화 하면서, 핑을 보낼 시간이 경과하면(정해진 몇초동안 패킷전송이 없을때) 전송. 훔..캐주얼게임이라 UDP소켓이 쓸데가 꽤 있는지라(방목록갱신 등에 좋음)..어차피 생성되 있는 UDP패킷으로 전송. 

서버에서는 받은 패킷을 궂이 recv큐에 넣을 필요없이 worker쓰래드 단에서 시간재서 차단. 
너무 기본적인건가요?..ㅎㅎ
위로
 
비회원
손님





올리기스피트핵 체크 루틴들은 안넣으시나요?올려짐: 2006-09-19 14:01
인용과 함께 답변 이 게시물을 del.icio.us에 추가

저같은 경우는 주기적으로 서버와 클라이언트간에 타임스탬프를 찍어 교환하는 방식으로 
스피드핵을 걸러내고 있습니다. 각 클라이언트별 핑타임까지 고려해서 걸러내보니 
국내 환경에서 110%까지는 선의의 피해자 없이 잘 돌아가는 것으로 파악됩니다. 
어차피 이렇게 주기적으로 패킷을 주고 받다보니 
이녀석을 활용해서 Keep Alive 체크도 하고 있습니다. 
최대 1분동안 응답이 없으면 죽은 클라이언트로 간주하고 있습니다. 
물론 중간에 로딩 타임 등에 대한 고려가 필요합니다.
위로
 
myevan



가입: 2003년 3월 4일
올린 글: 976

올리기Re: 스피트핵 체크 루틴들은 안넣으시나요?올려짐: 2006-09-19 14:23
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
저같은 경우는 주기적으로 서버와 클라이언트간에 타임스탬프를 찍어 교환하는 방식으로 
스피드핵을 걸러내고 있습니다. 각 클라이언트별 핑타임까지 고려해서 걸러내보니 
국내 환경에서 110%까지는 선의의 피해자 없이 잘 돌아가는 것으로 파악됩니다. 
어차피 이렇게 주기적으로 패킷을 주고 받다보니 
이녀석을 활용해서 Keep Alive 체크도 하고 있습니다. 
최대 1분동안 응답이 없으면 죽은 클라이언트로 간주하고 있습니다. 
물론 중간에 로딩 타임 등에 대한 고려가 필요합니다.


쓰레드 논외지만 스피드핵 이야기가 나와서... 
컴퓨터 시계들이 그리 정확하지 않기 때문에 
주기적으로 시간 동기화 프로토콜을 사용하시는 것이 좋습니다. 

제가 사용한 방법중 가장 효과가 좋았던 것은 
그냥 스피드핵을 인정하고 속도가 빨라진 만큼 데미지에 패널티를 주는 방식입니다. 
(한번 공격할 시간에 두번 공격했다면 1/2 데미지) 

어차피 게임에서 공격은 일정한 랜덤 범위가 있기 마련인데 
여기에 게임 외적인 요소 - 즉 네트워크 렌턴시 - 요소를 추가시키는 것이죠. 

300~400밀리초 간격으로 떨어져있던 패킷이 몰아서 오는 경우는 극히 드물기 때문에 
게임이나 유저 개개인에게 크게 지장은 주지 않으면서 상당히 공평한 결과를 얻을 수 있습니다.
_________________
빗자루네 http://www.myevan.net >_<b
위로
사용자 정보 보기 쪽지 보내기 글 올린이의 웹사이트 방문 
laster40



가입: 2005년 1월 12일
올린 글: 98
소속: 무소속

올리기Re: 결국 IOCP 비정상 처리는 어떻게...?올려짐: 2006-09-21 03:41
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:


고민하다가 SIO_KEEPALIVE_VALS 라는 소켓 옵션을 사용해볼까 해서 테스트 해봤는데 

무언가 잘못됐는지 제대로 동작을 안하네요. 

열린 connection에 SIO_KEEPALIVE_VALS 5초 옵션을 주고 연결된 클라이언트의 랜선을 확~ 

뽑았는데, 5분이 지나도 감지 못합니다. -0-;;;; 


혹시 이것을 IOCP에서 테스트 해보시거나 사용해 보신분도 의견을 주시면 감사하겠습니다.



sio_keepalive_vals -_-옵션 켜구 하면 보통 로컬에선 감지가 될텐데^^;;; 


rfc문서에 keepalive 는 기본구현사항(용어가 있잖아요? 꼭 구현해야 한다는 뭐 그런;; )이 아닙니다. 
권장 사항(recommand? - rfc문서들의 레벨이 있던데 정확히 모르겟군요;; )이죠...그래서 네퉉크 장비를 만드는 사람이... 좀 바쁘시면 안만들어두 되는 그런것이죠 아무리 옵션을 세팅했다고 해서... 될일은 아니죠 모든 장비가 keepalive을 지원하는 그런일은 바라지 않는것이...;; 

랜카드가 어떤건지 모르겟으나 제 경험상 로컬에서 저 옵션을 켠것고 끈것은 확실히 차이가 있었습니다.-0-
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
laster40



가입: 2005년 1월 12일
올린 글: 98
소속: 무소속

올리기Re: 스피트핵 체크 루틴들은 안넣으시나요?올려짐: 2006-09-21 03:47
인용과 함께 답변 이 게시물을 del.icio.us에 추가

비회원 씀:
저같은 경우는 주기적으로 서버와 클라이언트간에 타임스탬프를 찍어 교환하는 방식으로 
스피드핵을 걸러내고 있습니다. 각 클라이언트별 핑타임까지 고려해서 걸러내보니 
국내 환경에서 110%까지는 선의의 피해자 없이 잘 돌아가는 것으로 파악됩니다. 
어차피 이렇게 주기적으로 패킷을 주고 받다보니 
이녀석을 활용해서 Keep Alive 체크도 하고 있습니다. 
최대 1분동안 응답이 없으면 죽은 클라이언트로 간주하고 있습니다. 
물론 중간에 로딩 타임 등에 대한 고려가 필요합니다.



저도 같은 방법으로 구현했습니다. 반가워서-0-;; 



|------------------------------|------------------------------|------------------------------|
^ ^ ^ ^ ^ ^


^에서 ^ 까지만 들어와 주면-_- 좋아요 라고 세팅해주고 벗어나면 누적시켜서 처리하고 있습니다~
위로
사용자 정보 보기 쪽지 보내기 MSN 메신저 
비회원
손님





올리기ACE에 있는 Ping을 이용하라는 의미..올려짐: 2006-09-21 10:22
인용과 함께 답변 이 게시물을 del.icio.us에 추가

Ping을 이용하라는 의미가 클라에서 나 살아있소라는 패킷을 보내는거였습니까? 

서버에서 패킷을 성공적으로 보내고 
클라에서 받고 난 이후에 클라에서 랜선을 뽑는다던지 PC를 끈다던지 했을 경우, 
서버에서 다음 패킷을 날려야만 서버에서 연결끊김을 알수 있다. 

위와 같은 가정하에 서버에서 너 살아있냐라는 Ping패킷을 보내면 클라이언트 쪽 
연결이 종료됨을 알수 있기때문에 Ping을 보내라는 것으로 알고 있었는데 아닌가요?

DllMain에서 하지 말아야 할 것들

저장소/VC++

야호~~~

FreeLibrary를 할 때 리턴이 안 되는 문제가 있었다.

아오! 대체 왜 그러는지 찾는데 몇시간이 걸린건가 @_@

원인은 CoUninitialize 호출 후 반환되지 않는 문제로 인한 것이었다.


MSDN에 CoUninitialize를 살펴보면 아래와 같은 내용이 있다.

Because there is no way to control the order in which in-process servers are loaded or unloaded, do not call CoInitializeCoInitializeEx, or CoUninitialize from the DllMainfunction.


CoInitialize 처리는 DllMain에서 하지 않았지만 CoUninitalize는 DllMain의 DLL_PROCESS_DETATCH 에서 처리했던게 문제였다.

사실 중간에 CoInitialize/CoUninitialize를 사용했다는 것을 몰랐던 내 문제지만 ㅋㅋ

객체 해제 과정을 따로 처리한 다음에 DllMain에서는 아무 것도 처리하지 않게 만들면 쉽게 해결 가능할 것 같은데

안 해봐서 모르니 일단 패스.


원인을 찾다보니 DLL지옥 관련된 여러 내용들이 있는 것 같다.

정리를 잘 해주신 분들이 있으니까 참고하도록 하자.


참고 1 : http://ancdesign.tistory.com/43

참고 2 : 신영진님의 옛날 블로그 (http://www.jiniya.net/tt/788)


다음 내용은 신영진님의 블로그에서 낼름 복사한 것이다. (혹시 없어질까봐 ^^;)

경고!!! 
DllMain에서 다음 작업들은 절대로 하지 말 것.

  1. LoadLibrary, LoadLibraryEx 호출. 데드락이나 크래시를 유발한다.
  2. 다른 스레드와 동기화. 데드락을 유발한다.
  3. 로더 락을 획득하려는 코드가 가지고 있는 동기화 오브젝트를 획득하려는 시도. 데드락을 유발한다.
  4. CoInitializeEx를 사용한 COM 스레드 초기화. 특정 조건이 충족될 경우 이 함수는 LoadLibraryEx를 호출한다.
  5. 레지스트리 함수들. 이 함수들은 advapi32.dll에 구현되어 있다. advapi32.dll이 초기화 되지 않았다면 크래시가 발생할 수 있다.
  6. CreateProcess 호출. 프로세스 생성은 다른 DLL을 로드할 수 있다.
  7. ExitThread 호출. DLL 디태치(detach) 과정 중에 스레드를 종료하면 로더 락을 다시 획득하도록 만들 수 있다. 이는 데드락이나 크래시가 유발된다.
  8. CreateThread 호출. 동기화만 하지 않는다면 스레드 생성은 괜찮을 수 있다. 하지만 위험하다.
  9. 네임드 파이프나 네임드 오브젝트 생성 (2000만 해당한다). 윈도우 2000에서 네임드 오브젝트 생성은 터미널 서비스 DLL에서 구현되어 있다. 해당 DLL이 초기화되어 있지 않다면 크래시.
  10. CRT에 포함된 메모리 관리 함수들. CRT DLL이 초기화되어 있지 않다면 크래시.
  11. user32.dll이나 gdi32.dll에 포함된 함수 호출. 일부 함수들은 다른 DLL을 로드하고, 이 사실은 크래시가 발생할 수 있다는 것을 의미한다.
  12. 관리된 코드 사용.

* 가장 아름다운 DllMain은 존재하지 않는 것이다 (비어 있는 함수 바디).
** 그래도 먼가 하고 싶다면 kernel32.dll에 포함된 함수 중에 위에서 언급되지 않은 것들만 쓰도록 한다. kernel32.dll이 초기화는 운영체제가 보장해 준다. 
*** 글로벌 오브젝트에 대한 초기화 코드 또한 DllMain 과정에 포함된다. 따라서 글로벌 오브젝트의 생성자 내지는 초기화 함수 부분에 위에서 언급한 내용이 있어서는 안된다.
**** 초기화를 하지 말란 소린가? 아니다. 지연시키라는 말이다.





GetQueuedCompletionStatus의 0 transferred bytes (4)

저장소/VC++

경험 부족이네, 확신이 없어 여기저기 퍼온다. ㅋ

긁어다 붙였는데 잘 붙네.. 원치 않는 것 까지.. ㅡㅜ


원문 : http://www.devpia.com/MAEUL/Contents/Detail.aspx?BoardID=50&MAEULNo=20&no=722711&ref=722690



 iocp 서버만들때 클라이언트가 연결을 끊었을경우  | VC++ 일반2008-05-18 오후 10:16:41
정종현 (jjjjrr)  정종현님께 메시지 보내기정종현님을 내 주소록에 추가합니다.정종현님의 개인게시판 가기번호: 722690  / 읽음:143

안녕하세요

iocp 서버만들때

클라이언트가 연결을 끊었을경우

어떤이벤트가 발생하는지...

아래코드에서보면

if(dwBytesTrans == 0)   // 전송받은 것이 없다면 클라이언트가 종료한 경우
이경우가 클라이언트가 종료시의경우인데

bRet 가 false 이고

   ErrorCode = GetLastError();
   if (ERROR_NETNAME_DELETED == ErrorCode) 

인경우도 클라이언트의 연결이 끊어진경우라고하던데

이두경우의 차이점이 뭔가여?

 

 

  bRet = GetQueuedCompletionStatus(pIOCP->m_hIOCP, &dwBytesTrans, reinterpret_cast<ULONG_PTR*>(&pClient),
   reinterpret_cast<LPOVERLAPPED*>(&pIO), INFINITE);
  if(bRet)   // 에러상태를 점금한다
  {
   if((ULONG_PTR)pClient == THREAD_DIE)  // 스레드 강제종료
   {
          int ErrCode = WSAGetLastError();
    TRACE("IOCP 스레드 강제종료: %d\n", ErrCode);
       //pIOCP->CloseClient(pClient, FALSE);
    return FALSE;
   }
  }
  else
  {
   ErrorCode = GetLastError();
   if (ERROR_NETNAME_DELETED == ErrorCode) 

   {
   }
   continue;
  }

  if(dwBytesTrans == 0)   // 전송받은 것이 없다면 클라이언트가 종료한 경우
  {
   continue;
  }

이 글에 답변 등록하기
 [답변].2008-05-19 오전 12:02:01
박인규 (linuxian)  박인규님께 메시지 보내기박인규님을 내 주소록에 추가합니다.박인규님의 개인게시판 가기번호: 722698  

ERROR_NETNAME_DELETED은 IO작업중인 상태에서 접속이 끊긴 것입니다.

비정상적 종료라고 보시면 되겠구요.

 

recv 했을 때 버퍼의 크기가 0이라면 정상적인 종료로 보시면 됩니다.

 

이 글에 답변 등록하기
         [답변]클라이언트의 연결이 끊어진경우가2008-05-19 오전 7:22:09
정종현 (jjjjrr)  정종현님께 메시지 보내기정종현님을 내 주소록에 추가합니다.정종현님의 개인게시판 가기번호: 722710  

답변감사합니다

혹시 이두경우외에 클라이언트의 연결이 끊어진경우가

있을까여?

ERROR_NETNAME_DELETED 상태를 몰라서 한참헤멨는데

다른경우는 없을런지...

 

이 글에 답변 등록하기
 [답변].2008-05-19 오전 7:39:20
박인규 (linuxian)  박인규님께 메시지 보내기박인규님을 내 주소록에 추가합니다.박인규님의 개인게시판 가기번호: 722711  

GetQueuedCompletionStatus 이 함수가 거짓을 리턴되었다는 것은 요청한 IO 작업을 완료하지 못했다는 뜻입니다.

즉 IO 작업중에 또는 작업시도할때 상대편에 무슨 일이 생긴 것이지요.

왜냐하면 TCP는 기본적으로 연결을 보장하니까요.

이때 에러코드가 ERROR_NETNAME_DELETED 입니다. 솔직히 이건 문서에도 잘 나와있지 않은거라

저도 경험상 찾아낸 기억이 나네요.

 

 

GetQueuedCompletionStatus 은 TRUE를 리턴하면 IO작업을 완료했다는 뜻입니다.

Iocp에서 WSARecv를 걸어 두죠?

따라서 Recv에서 0바이트를 리턴(IO 완료)했다는 의미는 접속이 끊어진 걸로 간주하는 겁니다.

이것은 왜 그렇게 했느냐.. ㅎㅎ 처음 만든 사람이 그렇게 한거죠. 전송받은 바이트는 항상 0보다 클테니

0을 리턴하면 접속 종료로 하자 머 이런..

GetQueuedCompletionStatus의 0 transferred bytes (3)

저장소/VC++

음.. 요렇게도 쓰는구나. +ㅁ+

근데 내가 찾는 것과는 다르다.



원문 출처 : http://ykpk3733.egloos.com/8780



IOCP 를 공부중에 우연히 0 size buffer 란 기법을 알게 되고 여기저기 자료를 보면서 공부한 내용을 정리한것이다.

 

조금이라도 도움이 되었으면 하는 마음으로 포스팅을 한다.

 

-----------------------------------------------------------------------------------

1. "기본 WSAOVERLAPPED의 구조"

다음 구조체는 WSARecv() 혹은 WSASend() 함수에 넘겨주어야 하는 일반적인WSAOVERLAPPED 구조체이다.

 

typedef struct PER_IO_DATA : public WSAOVERLAPPED {
 char  Buffer[DATA_BUF_SIZE];
 int operation;
}PER_IO_DATA;

 

이 구조체에는 Buffer라는 변수가 포함되어 있다.

즉, 이것은 0 SIZE 버퍼가 아닌 클라이언트마다 각각의 버퍼를 할당해주는 방식이다.


2. "0 SIZE 버퍼"

1번과 같은 방식은 대량 연결용 서버의 경우엔 불필요한 메모리를 너무 많이 잡아 먹고, 관리도 힘들어진다.

이런 경우에는 "0 SIZE 버퍼" 를 이용하는 방법이 있다.

아래는 "0 SIZE 버퍼" 의 구조체 정보이다.

 

typedef struct PER_IO_DATA : public WSAOVERLAPPED {
 int operation; // OP_RECV, OP_SEND
}

 

보는바 와 같이 버퍼를 아예 제거 해버렸다.

그리고, 다음과 같이 사용 하면 된다.

 

pData = new PER_IO_DATA;
if( pData == NULL )
 return FALSE;

pData->Operation = OP_RECV;

wsabuf.buf = NULL; // 버퍼를 아예 제공하지 않는다.
wsabuf.len = 0;  // Recv할 최대 크기를 0으로 만든다.
flag = 0;
ret = WSARecv( sock, &wsabuf, 1, &&bytes, &flag, pData, NULL );
if( ret == SOCKET_ERROR && WSAGetLastError() != ERROR_IO_PENDING ){
 delete pData;
 return FALSE;
}

 

이렇게 하면, 해당 소켓으로 데이터가 들어왔을때 IOCP는 Worker thread를 깨워

처리하도록 한다. 그런데, 문제는 버퍼가 없으니 받은 데이터가 없다.

3. Worker thread에서 데이터 처리하기

아래 코드는 Worker thread의 핵심이 되는 함수이다.

 

ret = GetQueuedCompletionStatus(
 m_cp,    // IOCP Handle
 &bytes,    // 송,수신된 byte 수
 (LPWORD)&sock,   // Completion Key
 (LPWSAOVERLAPPED *)&pid, // WSAOVERLAPPED 데이터
 INFINITE );

 

3번째 PARAMETER인 sock은 Completion Key 로 SOCKET HANDLE 을 바로 사용한 경우이다.

일반적으로 bytes 값이 "0"이면 연결이 끊긴 것으로 처리를 하였다.

하지만 "0 SIZE 버퍼"를 사용했을 경우엔 무조건 bytes 값이 "0" 로 리턴된다.

따라서, 이 경우에는 끊긴 것으로 판단하지 말고 일단 데이타가 들어온 것이라고 판단해야 한다.

버퍼를 0로 만들었기 때문에 IOCP는 소켓으로 수신된 데이터를 아직 손대지 않은 상태이다.

이제 이것을 읽어 내야 하는데, 방법은 간단하다.

일반적인 송,수신 소켓 함수로 읽어내면 된다.

프로토콜을 이쁘게 정의하면, 수신되어야할 데이터가 얼마인지를 알 수 있는 경우가 있는데,

이 경우는 그 만큼 읽혀 질때까지 recv()를 하면되고,

만일 모를 경우는 nonblocking 방식으로 WSAEWOULDBLOCK이 될 때까지 recieve를 하면 된다.

이렇게 데이터를 모두 읽어서 처리하였다면,

다시 WSARecv() 를 사용하여 IOCP에 요청을 한다.

물론 생성된 pid는 이곳에서 제거를 해도 좋고, 계속 사용해도 좋다.


GetQueuedCompletionStatus의 0 transferred bytes (2)

저장소/VC++

음.. 


원문 출처 : http://copynull.blog.me/10078931630


네트워크 접속이 비정상으로 끊겼을 때는 
GetQueuedCompletionStatus()함수가 FALSE를 리턴하고 수신바이트 크기가 0(zero) 입니다. 

정상적으로 끊겼을 때는 
GetQueuedCompletionStatus()함수가 TRUE를 리턴하고 수신바이트 크기가 0(zero) 입니다. 
이 때 GetQueuedCompletionStatus()에서 Overlapped Recv I/O 가 리턴됩니다. 

 

비정상적종료 :   리턴값 false, 수신바이트 0

정상적인종료 :   리턴값 true,  수신바이트 0

 

즉 간단히 코드로 설명해보면

 

BOOL result = GetQueuedCompletionStatus(......);

 

if( result == FALSE || recvBytes == 0 )

{

        if( result == FALSE )

        {      비정상 종료 알려주는 코드  WSAGetLastError()로 알림   }

      // 정상 종료 코드

      // 종료를 진행한다....

}

 

IO_TYPE로 검사후 진행되는 코드의 경우 아래와 같이 진행하면 되겠다.

if ( !result || ( result && !recvBytes ) )
  {
   if (OverlappedEx->IoType == IO_ACCEPT)    // 데이터가 없어도 IO_ACCEPT라면 접속함수로 넘김
    OnIoConnected(Object);
   else                                                    // 그것도 아니면 완전 모두 에러처리
    OnIoDisconnected(Object);

   continue;
  }