TCP-IP 윈도우 소켓 프로그래밍

[TCP/IP] 2장. 윈도우 소켓 시작하기

민돌v 2021. 4. 7. 17:23

오류 처리

1. 오류처리 유형

오류처리 방법에 따라 다음 세가지 유형으로 나눌 수 있다.

1) 오류를 처리할 필요가 없는경우

    : 리턴값이 없거나 호출 시 항상 성공하는 일부 소켓 함수

 

2) 리턴 값만으로 오류를 처리하는 경우

    : WSAStartup() 함수

 

3) 리턴 값으로 오류 발생을 확인하고, 구체적인 내용은 오류 코드로 확인하는 경우

   : 대부분의 소켓 함수

 

※ 1,2 유형은 특별한 경우이다.

※ 대부분의 소켓함수는 3유형으로 처리한다. 


2. 오류 코드 얻기

1) int WSAGetLastError(void)

   (사용 예시)

if (소켓함수(...) == 실패) {
	int errcode = WSAGetLastError();
	printf(errcode에 해당하는 오류 메시지);
}
  • WSAGetLastError()함수의 리턴 값을 화면에 그대로 표시할 경우 사용자가 직접 오류코드의 의미를 알아야 하므로 불편하다.
  • FormatMessage() 함수를 이용하여 오류코드에 대응하는 오류메세지를 "문자열"로 얻을 수 있다.

 

2) FormatMessage() 함수

   (사용 예시)

DWORD FormatMessage (
	DWORD dwFlags, // 옵션
	LPCVOID lpSource, // NULL
	DWORD dwMessageId, // 오류 코드
	DWORD dwLanguageId, // 언어
	LPTSTR lpBuffer, // 오류 문자열 시작 주소
	DWORD nSize, // 0
	va_list* Arguments // NULL
) ;

성공: 오류 메시지의 길이, 실패: 0

가. dwFlags : FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM 값을 사용

  • "~~~BUFFER"는 오류 메시지를 저장할 공간을 FormatMessage()가 알아서 저장한다는 의미이다.
  • "~~~SYSTEM"은 운영체제로부터 오류 메시지를 가져온다는 의미이다.
  • dwFlags를 이와 같이 설정한다면
    • ipSource = Null
    • nSize = 0
    • Arguments = Null 값이 사용된다.

나. dwMessage : 오류 코드를 나타내며, WSAGETLastError() 함수의 리턴값을 여기에 넣는다.

다. dwLanguageld :오류 메시지를 표시할 언어

  • MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT)를 사용하면 사용자가 설정한 Local 언어로 설정된다.

라. IpBuffer : 오류 메시지의 시작주소가 저장

 

 

3)  err_equit()함수 정의(FormatMessage() 함수를 이용)

void err_quit(char *msg)
{
    LPVOID lpMsgBuf;
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER  | FORMAT_MESSAGE_FROM_SYSTEM, NULL, WSAGetLastError(),
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),(LPTSTR)&lpMsgBuf, 0, NULL
     );
    MessageBox(NULL, (LPCTSTR)lpMsgBuf, msg, MB_ICONERROR);
    LocalFree(lpMsgBuf);
    exit(1);
}

 

함수 사용 예

if(socket(...) == INVALID_SOCKET) err_quit("socket()");
if(bind(...) == SOCKET_ERROR) err_quit("bind()");

4)  err_distplay함수 정의(사소한 오류)

    :  사소한 오류가 발생할 때마다 응용 프로그램을 종료하는 일은 바람직하지 않다.

       이 경우에는 err_equit()함수 대신 err_display함수를 사용한다.

void err_display(char *msg)
{
    LPVOID lpMsgBuf;
    FormatMessage(
    FORMAT_MESSAGE_ALLOCATE_BUFFER
    | FORMAT_MESSAGE_FROM_SYSTEM,
    NULL, WSAGetLastError(),
    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
    (LPTSTR)&lpMsgBuf, 0, NULL);
    printf("[%s] %s", msg, (char *)lpMsgBuf);
    LocalFree(lpMsgBuf);
}

원속 초기화와 종료

1. 윈속 응용 프로그램의 공통 구조

윈속 응용 프로그램의 공통 구조

1) 윈속 초기화

    : 모든 윈속  프로그램은 소켓 함수를 호출하기 전에 반드시 윈속 초기화 함수인 WSAStartup()함수를 호출해야한다.

 

  1. WSAStartup()함수는 프로그램에서 사요할 윈속 버전을 요청함으로써 윈속 라이브러리(WS2_32.DLL)를 초기화하는 역할을 한다.
  2. WSAStartup()함수가 실패할 경우 WS2_32.DLL이 메메리에 로드되지 않는다.
  3. 이 경우에는 WSAGetLastError()함수가 리턴하는 오류 코드는 부정확하므로 WSAStartu()함수는 직접 오류코드를 리턴하도록 설계되어 있다.

(WSAStarup 예시)

int WSAStartup (
  WORD wVersionRequested,
  LPWSADATA lpWSAData
);
  • VersionRequested – 프로그램이 요구하는 최상위 윈속 버전. 하위 8비트에 주 버 전을, 상위 8비트에 부 버전을 넣어서 전달
  • lpWSAData – 윈도우 운영체제가 제공하는 윈속 구현에 관한 정보를 얻을 수 있음(거의 사용 안 함)

2) 원속 종료

int WSACleanup(void);

 


소켓 생성과 닫기

1. 소켓 생성  

SOCKET socket (
    int af, // 주소 체계
    int type, // 소켓 타입
    int protocol // 프로토콜
);

1) 소켓 디스크립터(socket descriptor)

    : 사용자가 요청한 프로토콜을 사용해 통신할 수 있도록 내부적으로 리소스를 할당하고, 이에 접근할 수 있는 일정의 핸들값(Socket 타입, 32비트 정수)를 리턴하는 값

 

2) 주소 체계

  • 통신을 하려면 통신 상대를 유일하게 지정할 수 있는 주소가 필요하다.
  • 주소 체계란 이러한 주소 지정 방법을 지칭하는 용어이다.
  • 주소 체계는 네트워크 프초토콜의 종류에 따라 달라진다.

3) 소켓 타입

  • 소켓 타입은  사용할 프로토콜의 특성을 나타내는 값이다.
  • 자주 사용하는 소켓 타입을 요약하면 아래와 같다.

 

소켓 타입 특성
SOCK_STREAM  신뢰성 있는 데이터 전송 기능 제공, 연결형 프로토콜 
SOCK_DGRAM  신뢰성 없는 데이터 전송 기능 제공, 비연결형 프로토콜

 

4) 프로토콜

    : 주소 체계와 소켓 타입이 같더라도 해당 프로토콜이 두 개 이상 존재할 경우 프로토콜을 명시적으로 지정

 

- TCP나 UDP 프로토콜은 주소 체계와 소켓 타입만으로 프로토콜을 결정할 수 있으므로 대개는 프로토콜 부분에 0사용

 

ex)

SOCKET tcp_socket = socket(AF_INET, SOCK_STREAM, 0);

2. 소켓 닫기

int closesocket ( 
	SOCKET s
);