과목명 : 컴퓨터 통신(Computer communication)
수업일자 : 2022년 09월 19일 (월)
1. 오류 처리(Error Handling)
1-1 정의
- 네트워크 프로그램에서는 여러 원인 때문에 오류가 발생할 수 있으며 발생 확률도 비교적 높습니다. 이에 따라 함수 호출 시, 오류를 체크하여 사용자에게 오류 내용을 알려주는 것이 매우 중요합니다.
- 학습할 윈속 함수는 오류 처리 방법을 다음과 같이 세 가지로 나눌 수 있습니다.
(1) 오류를 처리할 필요가 없는 경우
- return 값이 존재하지 않거나 호출 시 항상 성공하는 일부 소켓 함수
(2) return 값만으로도 오류를 처리하는 경우
- WSAStartup() 함수
(3) return 값으로 오류를 확인하고, 구체적인 오류 내용은 코드로 확인하는 경우
- 대부분의 소켓 함수
1-2 WSAGetLastError() 함수
- 소켓 함수 호출 결과 오류가 발생했다면 해당 함수를 사용하여 오류 코드를 얻을 수 있습니다.
- int WSAGetLastError(void);
- 해당 함수의 사용 예시는 아래 코드와 같습니다.
if(소켓 함수(...) == 실패) {
int errorcode = WSAGetLastError();
printf(errcode에 해당되는 오류 메시지);
}
- 해당 함수의 return 값을 화면에 그대로 표시할 경우 사용자가 오류 코드의 의미를 직접 알아내야 하는 불편함이 생깁니다. 이에 따라 FormatMessage() 함수를 사용하면 오류코드에 대응하는 오류 메시지를 얻을 수 있습니다.
- err_display() 함수는 err_quit() 함수에서 마지막 한 행을 제거하고 출력함수로 MessageBox() 대신 printf()를 사용합니다.
- 이 함수는 오류 메세지를 출력하되, 응용 프로그램을 종료하지 않습니다.
2. 윈속의 초기화와 종료
아래 그림은 모든 윈속 응용 프로그램의 공통 구조를 나타냅니다. 2번에서는 윈속의 초기화와 종료 방법을 알아보겠습니다.
2-1 윈속 초기화 함수 : WSAStartup()
- 모든 윈속 프로그램은 소켓 함수를 호출하기 전에 반드시 윈속 초기화 함수인 WSAStartup()을 호출해야 합니다.
- WSAStartup() 함수는 사용할 윈속 버전을 요청함으로써 윈속 라이브러리(WS2_32.DLL)를 초기화합니다.
- 해당 함수는 오류 코드를 직접 Return할 수 있도록 설계되어 있으며 구조는 아래와 같습니다.
int WSAStartup(
WORD wVersionRequested,
LPWSADATA lpWSAData
);
(1) wVersionRequested
- 프로그램이 요구하는 최상위 윈속 버전입니다.
- 하위 8비트에 주 버전, 상위 8비트에 부 버전을 넣어서 전달합니다.
- Ex) 윈속 3.2 version, 0x0203 또는 MAKEWORD(3, 2)
(2) lpWSAData
- WSADATA 구조체를 전달하면 이를 통해 윈도우 운영체제가 제공하는 윈속 구현에 관한 정보를 얻을 수 있습니다.
2-2 윈속 버전 지원
운영체제 | 윈속 버전 |
Windows 95 | 1.1(2.2) |
Windows 98 / ME, Windows NT / 2000 / XP / 2003 Server, Windows Vista / 2008 Server / 7 |
2.2 |
Windows CE | 1.1(2.2) |
2-3 윈속 종료 함수 : WSACleanup()
- 프로그램을 종료할 때는 윈속 종료 함수인 WSACleanup() 함수를 호출해야 합니다.
- 해당 함수는 윈속 사용을 중지함을 운영체제에게 알리고 사용됐던 시스템 자원(Resource)를 반환하게 됩니다.
- 함수 호출에 실패할 경우 WSAGetLastError() 함수를 호출하여 구체적인 오류 코드를 얻을 수 있습니다.
- 형식은 아래와 같습니다.
int WSACleanup(void);
2-4 윈속을 초기화하고 종료하는 간단한 프로그램 작성
// Chapter02.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32")
int _tmain(int argc, _TCHAR* argv[])
{
// 윈속 초기화
WSADATA wsa;
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0) return 1;
MessageBox(NULL, "윈속 초기화 성공", "알림", MB_OK);
//윈속 종료
WSACleanup();
return 0;
}
해당 프로그램을 실행하면 윈속 초기화가 성공했음을 아래와 같이 알 수 있습니다.
3. 소켓 생성과 닫기
위의 과정들을 통해 윈속이 초기화되었고, 이제는 소켓을 생성할 준비가 되었습니다.
아래 그림은 소켓을 생성하고 닫는 방법에 대한 그림이며 해당 방법들을 알아보도록 하겠습니다.
3-1 소켓 생성하기
- 소켓을 사용하여 통신하기 위한 기본 조건은 통신하는 양단이 같은 프로토콜을 사용해야 합니다.
- 이에 따라 TCP로 통신할 것인지, UDP로 통신할 것인지 정의해야 합니다.
- socket() 함수는 사용자가 요청한 프로토콜을 이용해 통신할 수 있도록 내부적으로 자원을 할당하고, 이에 접근할 수 있는 핸들값(SOCKET 타입, 32비트 정수)을 리턴하며 이를 소켓 디스크립터(Socket descriptor)라고 합니다.
- 소켓 디스크립터는 각종 소켓 함수를 호출할 때, 인자로 전달해 사용하며 형식은 아래와 같습니다.
SOCKET socket(
int af,
int type,
int protocol
}
(1) af : 주소 체계를 지정하는 인자입니다.
(2) type : 소켓 타입을 지정하는 인자입니다.
(3) protocol : 어떤 프로토콜을 사용할 것인지에 대한 인자입니다.
해당 인자들의 의미를 하나씩 알아보겠습니다.
3-2 주소 체계
- 네트워크 통신을 하기 위해 상대를 지정할 수 있는 주소가 필요하고 이러한 주소 체계는 프로토콜의 따라 달라지므로 주소 체계 지정은 사용한 프로토콜을 지정하기 위한 첫 번째 단계입니다.
- winsock2.h 또는 ws2def.h 헤더 파일을 보면 아래 코드와 같이 AF로 시작하는 상수를 찾을 수 있으며 사용할 프로토콜에 대응하는 값을 선택해 socket() 함수의 첫 번째 인자로 전달합니다.
#define AF_INET 2 // Internetwork : UDP, TCP etc...
#define AF_INET6 23 // Internetwork version 6
#define AF_IRDA 26 // IrDA
#define AF_BTH 32 // Bluetooth RFCOMM / L2CAP protocols
3-3 소켓 타입
- 통신을 위해 사용할 프로토콜의 특성을 나타내는 값이며 자주 사용하는 소켓 타입은 아래의 표와 같습니다.
소켓 타입 | 특성 |
SOCK_STREAM | 신뢰성 있는 데이터 전송 기능 제공, 연결형 프로토콜 (TCP) |
SOCK_DGRAM | 신뢰성 없는 데이터 전송 기능 제공, 비연결형 프로토콜 (UDP) |
- TCP, UDP 프로토콜을 사용해 통신하려면, 아래의 주소 체계와 소켓 타입으로 설정해야 합니다.
- 주소 체계가 동일해도 소켓 타입을 다르게 정할 수 있으며 결과적으로 사용할 프로토콜의 종류가 달라지게 됩니다.
사용할 프로토콜 | 주소 체계 | 소켓 타입 |
TCP | AF_INET 또는 AF_INET6 | SOCK_STREAM |
UDP | AF_INET 또는 AF_INET6 | SOCK_DGRAM |
3-4 프로토콜 타입
- 주소 체계와 소켓 타입이 동일해도 이에 해당하는 프로토콜이 두 개 이상 존재할 수 있는 상황에선 명시적으로 프로토콜의 타입을 지정해 줘야 합니다.
- Socket() 함수의 세 번째 인자에 해당하며 TCP, UDP 프로토콜을 사용하려면 주소 체계와 소켓 타입, 그리고 프로토콜 타입을 아래와 같이 지정할 수 있습니다.
사용할 프로토콜 | 주소 체계 | 소켓 타입 | 프로토콜 타입 |
TCP | AF_INET 또는 AF_INET6 | SOCK_STREAM | IPPROTO_TCP |
UDP | AF_INET 또는 AF_INET6 | SOCK_DGRAM | IPPROTO_UDP |
- TCP, UDP 프로토콜은 소켓 타입을 지정함으로써 프로토콜이 결정되므로 세 번째 인자는 0을 주게 됩니다.
사용할 프로토콜 | 주소 체계 | 소켓 타입 | 프로토콜 타입 |
TCP | AF_INET 또는 AF_INET6 | SOCK_STREAM | 0 |
UDP | AF_INET 또는 AF_INET6 | SOCK_DGRAM | 0 |
3-5 소켓 닫기
- 소켓을 사용한 통신을 마치면 시스템에게 관련 자원을 반환해야 합니다.
- closesocket() 함수를 사용하면 소켓을 종료하고 자원을 반환합니다.
int closesocket(
SOCKET s
)
3-6 소켓을 생성하고 닫는 프로그램 작성
// SocketOpenClose.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsock2.h>
#pragma comment(lib, "ws2_32")
// 소켓 함수 오류 출력 후 종료
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, (LPTSTR)&lpMsgBuf, msg, MB_ICONERROR);
LocalFree(lpMsgBuf);
exit(1);
}
int _tmain(int argc, _TCHAR* argv[])
{
// 윈속 초기화
WSADATA wsa;
if(WSAStartup(MAKEWORD(2,2), &wsa) != 0) return 1;
MessageBox(NULL, "윈속 초기화 성공", "알림", MB_OK);
// socket()
SOCKET tcp_sock = socket(AF_INET, SOCK_STREAM, 0);
if(tcp_sock == INVALID_SOCKET) err_quit("socket()");
MessageBox(NULL, "TCP 소켓 생성 성공", "알림", MB_OK);
// closesocket()
closesocket(tcp_sock);
//윈속 종료
WSACleanup();
return 0;
}
해당 프로그램을 컴파일, 링크 후 실행되는 결과는 아래와 같이 소켓이 정상적으로 생성됨을 알 수 있습니다.
- 학부에서 수강했던 전공 수업 내용을 정리하는 포스팅입니다.
- 내용 중에서 오타 또는 잘못된 내용이 있을 시 지적해 주시기 바랍니다.
'전공 수업 > 컴퓨터 통신(Computer Communication)' 카테고리의 다른 글
[6주 차] - 도메인 이름 시스템과 이름 변환 함수, DNS 서비스의 클라이언트 동작 원리 (2) | 2022.10.04 |
---|---|
[5주 차] - Windows 소켓 주소 구조체 (1) (2) | 2022.09.27 |
[3주 차] - Windows 소켓, 간단한 서버 소켓 프로그램 작성 (0) | 2022.09.12 |
[2주 차] - TCP/IP Protocol, 소켓(Socket)의 정의 (0) | 2022.09.06 |
[1주 차] - 수업 개요 (0) | 2022.08.30 |
댓글