오류 처리
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()함수를 호출해야한다.
- WSAStartup()함수는 프로그램에서 사요할 윈속 버전을 요청함으로써 윈속 라이브러리(WS2_32.DLL)를 초기화하는 역할을 한다.
- WSAStartup()함수가 실패할 경우 WS2_32.DLL이 메메리에 로드되지 않는다.
- 이 경우에는 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
);
'TCP-IP 윈도우 소켓 프로그래밍' 카테고리의 다른 글
[TCP/IP] 6장. 멀티 스레드 (0) | 2021.04.26 |
---|---|
[TCP/IP] 5장. 데이터 전송하기 (0) | 2021.04.14 |
[TCP/IP] 4장. TCP 서버- 클라이언트 (0) | 2021.04.09 |
[TCP/IP] 3장. 소켓 주소 구조체 다루 (0) | 2021.04.09 |
[TCP/IP] 1장. 네트워크와 소켓 프로그래밍 (0) | 2021.04.06 |