Coding Memo

[Winsock] WSAEINVAL(10022) 에러 (ConnectEx) 본문

Language/C++

[Winsock] WSAEINVAL(10022) 에러 (ConnectEx)

minttea25 2024. 3. 25. 14:25

에러 내용

 

::WSAGetLastError()로 얻은값이 10022 (WSAEINVAL)값으로 에러가 발생했다.

10022 에러

 

 

나의 경우 ConnectEx함수 호출 후, 위 에러가 나타났다. 찾아보니 인수가 잘못되었다는 에러였는데, 도대체 여러개의 인자들 중 무엇이 잘못되었는지 몰라서 당황했다. (필요한 인자가 nullptr도 아니었고, 잘못된 인자가 없었다.)

 

 

ConnectEx 문서를 보니 바로 이유를 알게 되었다...


 

해결

 

ConnectEx에 사용하는 소켓은 반드시 바인딩 되어 있어야 한다.

ConnectEx Socket 매개 변수

 

ConnectEx 호출 이전에 소켓에 ::bind를 통해 나중에 연결에 사용될 로컬 주소와 포트를 바인딩해주면 된다.

 

 

추가적으로 소켓에 대한 유의 사항을 정리하면

  1. 소켓은 바인딩되어 있어야 한다.
    (주의할 점은 연결 할 엔드포인트(보통 서버?)가 아니라, 연결 형성 시, 사용할 로컬 주소와 포트라는 것이다.)
  2. 소켓은 연결되어 있지 않은 상태여야 한다. (WSAEINVAL 에러가 아닌 다른 에러가 나타날 것이다.)
  3. 연결 지향형 소켓이어야 한다. (SOCK_STREAM, SOCK_RDM, SOCK_SEQPACKET)

 

Note: 물론 WSA_IO_PENDING은 제외!

 


원인

 

나의 경우는 ConnectEx에서 첫번째 인자인 소켓이 bind되어 있지 않은 소켓이어서 나타난 에러였다.

 

굳이 변명을 해보자면, 다른 언어들은 보통 연결을 할 때, OS 레벨에서 포트를 자동으로 할당해주기 때문에 신경을 쓰지 않아도 되는 부분이다...

(찾아보니, 단순 WSAAPI의 connect도 따로 바인딩이 필요가 없다! 그냥 ConnectEx는 반드시 소켓을 바인딩을 해주어야한다는 것만 기억하자.)

 

SOCKET _connectSocket;

SOCKADDR_IN bindAddr;
memset(&bindAddr, 0, sizeof(bindAddr));
bindAddr.sin_family = AF_INET;
bindAddr.sin_addr.s_addr = ::htonl(INADDR_ANY);
bindAddr.sin_port = ::htons(0); // any port

...

auto bind_result = ::bind(_connectSocket, reinterpret_cast<PSOCKADDR>(&bindAddr), sizeof(bindAddr));

// ::bind() will return SOCKET_ERROR(-1) if failed.;

 

bind 성공 후 ConnectEx를 호출 하니 해결!


https://learn.microsoft.com/ko-kr/windows/win32/api/mswsock/nc-mswsock-lpfn_connectex

 

LPFN_CONNECTEX(mswsock.h) - Win32 apps

ConnectEx 함수는 지정된 소켓에 대한 연결을 설정하고 연결이 설정되면 필요에 따라 데이터를 보냅니다.

learn.microsoft.com

https://learn.microsoft.com/ko-kr/windows/win32/winsock/windows-sockets-error-codes-2

 

Windows 소켓 오류 코드(Winsock2.h) - Win32 apps

WSAGetLastError 함수에서 반환된 Windows 소켓(Winsock) 오류 코드입니다.

learn.microsoft.com