[windows] SO_REUSEADDR

TIME_WAIT 된 소켓 재활용하는 옵션… 다아는 것 아님? 이럴 수도 있다.

윈도우즈에서 이 소켓 옵션을 사용하면, 프로세스를 띄울 때 이미 포트가 다른 프로세스에 바인드되어 있더라도 바인드 에러 없이 잘뜬다.-.,-

MS 설명에 따르면 대략 undefined behavior 인 듯 1

윈도우즈에서는 SO_EXCLUSIVEADDRUSE 를 쓰라고 한다. 이쪽 저쪽 다 되게 하려다 보니 귀찮은 일이 많네.

참고 링크
Differences Between Windows and Unix Non-Blocking Sockets
Winsock: strange conflict with SO_REUSEADDR
Why is SO_REUSEADDR disabled for Windows?
SO_REUSEADDR, SO_EXCLUSIVEADDRUSE
SO_REUSEADDR doesn’t have the same semantics on Windows as on Unix

Address Space Sandbox and /LARGEADDRESSAWARE

64bit 윈도우즈, 64bit cpu, 비주얼 스튜디오 x64 빌드 환경에서 링커에 “/LARGEADDRESSAWARE” 옵션 없이 그냥 빌드를 하면 2gb 이상의 주소에 접근할 수 없다.

x64 빌드에서 귀찮게 왜 저 옵션을 설정해야 2gb 이상 주소에 접근하는 걸까 궁금했는데, windows via c/c++ 5th 보다가 찾았다. 이유는
/LARGEADDRESSAWARE 가 없는 디폴트 x64 빌드 환경에서, 32bit에서 만들었던 코드가 다른 수정 없이 (그런게 없겠냐만은 조금은 수고를 덜어주겠지.) 작동하는 것을 보장하기 위해서다.

저 옵션을 활성화하지 않으면 시스템 (예를 들어 malloc) 에서 생성하는 포인터 주소 값들이 0x 7fff ffff 이하 값만 갖는다. (이런 이유로 윈도우즈 운영체제에서 2GB로 제한 된 가용 주소 공간을 address space sandbox라고 한다.) 32bit 에서 pointer 크기를 4byte 로 단정해서 쓴 경우도 많고, 2gb만 쓰니까 4byte pointer의 MSB 1 를 자기맘대로 이용한 경우가 있어서, 32bit 이상 주소를 시스템에서 반환하면 짤라먹을 까봐 저렇게 해준 것이다.

32bit 에서 /3GB 옵션 쓸 때 /LARGEADDRESSAWARE 도 같이 해줘야 한다고 해서 그때만 쓰는 걸로 헷갈렸는데 이제 정리됨.

결론. win32, x64 상관없이 2GB 이상의 주소 접근을 원한다면 무조건 /LARGEADDRESSAWARE 을 설정할 것. (‘무조건’에 대한 내용은 아래 업데이트 내용으로 대신합니다.)

UPDATE: leafbird 님 답글을 통해 2010 이상에서는 프로젝트 프로퍼티에 아무값도 안 넣어놓더라도 x64에서 /LARGEADRESSAWARE 가 적용됨을 알게 되었습니다.
아래는 제가 아무것도 없는 빈 솔루션을 vs2010 sp1 x64 debug 에서 빌드한 실행파일을 dumpbin 에서 확인한 내용입니다.

FILE HEADER VALUES
8664 machine (x64)
7 number of sections
543E854F time date stamp Wed Oct 15 23:31:43 2014
0 file pointer to symbol table
0 number of symbols
F0 size of optional header
22 characteristics
Executable
Application can handle large (>2GB) addresses

보시는 바와 같이 /LARGEADDRESSAWARE 가 적용될 경우 마지막 문장이

  1. most significant bit