TCP/IP 소켓 프로그래밍 2판(한빛아카데미, 2022) 연습문제 풀이
01 호스트의바이트 정렬 방식을 확인할 수 있는 함수를 정의하시오.
bool IsLittleEndianQ;
// 리턴값: 리틀 엔디언이면 true, 그렇지 않으면 false를 리턴한다.
bool IsBigEndian();
// 리턴값: 빅 엔디언이면 true, 그렇지 않으면 false를 리턴한다.
#include <stdio.h>
#include <stdbool.h>
// 리틀 엔디언을 확인하는 함수
bool IsLittleEndian()
{
unsigned int num = 1;
// 첫 번째 바이트가 1이면 리틀 엔디언
return (*(unsigned char *)&num == 1);
}
// 빅 엔디언을 확인하는 함수
bool IsBigEndian()
{
return !IsLittleEndian(); // 리틀 엔디언이 아니면 빅 엔디언
}
int main()
{
if (IsLittleEndian()) {
printf("호스트는 리틀 엔디언입니다.\n");
} else if (IsBigEndian()) {
printf("호스트는 빅 엔디언입니다.\n");
}
return 0;
}

02 IPAdclr 예제의 IPv4 주소를 변환하는 코드에서 inet_pton() 함수를 inet_addr() 함수로 변경하시오. 단, IPv6 주소를 변환하는 코드는 그대로 둔다.
03 IPAddr 예제의 IPv4 주소를 변환하는 코드에서 inet_ntop() 함수를 inet_ntoa() 함수로 변 경하시오. 단. IPv6 주소를 변환하는 코드는 그대로 둔다.
- 윈도우
#include "..\..\Common.h"
int main(int argc, char *argv[])
{
// 윈속 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return 1;
/*----------------*/
/* IPv4 변환 연습 */
/*----------------*/
// 원래의 IPv4 주소 출력
const char *ipv4test = "147.46.114.70";
printf("IPv4 주소(변환 전) = %s\n", ipv4test);
// inet_addr() 함수 사용 (inet_pton() 대신) 문제_02번
struct in_addr ipv4num;
ipv4num.s_addr = inet_addr(ipv4test);
printf("IPv4 주소(변환 후) = %#x\n", ipv4num.s_addr);
// inet_ntoa() 함수 사용 (inet_ntop() 대신) 문제_03번
char *ipv4str = inet_ntoa(ipv4num);
printf("IPv4 주소(다시 변환 후) = %s\n", ipv4str);
printf("\n");
/*----------------*/
/* IPv6 변환 연습 */
/*----------------*/
const char *ipv6test = "2001:0230:abcd:ffab:0023:eb00:ffff:1111";
printf("IPv6 주소(변환 전) = %s\n", ipv6test);
// inet_pton() 함수 사용 (IPv6 변환)
struct in6_addr ipv6num;
inet_pton(AF_INET6, ipv6test, &ipv6num);
printf("IPv6 주소(변환 후) = 0x");
for (int i = 0; i < 16; i++)
printf("%02x", ipv6num.s6_addr[i]);
printf("\n");
// inet_ntop() 함수 사용 (IPv6 변환)
char ipv6str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6num, ipv6str, sizeof(ipv6str));
printf("IPv6 주소(다시 변환 후) = %s\n", ipv6str);
// 윈속 종료
WSACleanup();
return 0;
}

- 리눅스
#include "../Common.h"
int main(int argc, char *argv[])
{
/*----------------*/
/* IPv4 변환 연습 */
/*----------------*/
const char *ipv4test = "147.46.114.70";
printf("IPv4 주소(변환 전) = %s\n", ipv4test);
// inet_addr() 함수 사용 (inet_pton() 대신) 문제_02번
struct in_addr ipv4num;
ipv4num.s_addr = inet_addr(ipv4test);
printf("IPv4 주소(변환 후) = %#x\n", ipv4num.s_addr);
// inet_ntoa() 함수 사용 (inet_ntop() 대신) 문제_03번
char *ipv4str = inet_ntoa(ipv4num);
printf("IPv4 주소(다시 변환 후) = %s\n", ipv4str);
printf("\n");
/*----------------*/
/* IPv6 변환 연습 */
/*----------------*/
const char *ipv6test = "2001:0230:abcd:ffab:0023:eb00:ffff:1111";
printf("IPv6 주소(변환 전) = %s\n", ipv6test);
// inet_pton() 함수 사용 (IPv6 변환)
struct in6_addr ipv6num;
inet_pton(AF_INET6, ipv6test, &ipv6num);
printf("IPv6 주소(변환 후) = 0x");
for (int i = 0; i < 16; i++)
printf("%02x", ipv6num.s6_addr[i]);
printf("\n");
// inet_ntop() 함수 사용 (IPv6 변환)
char ipv6str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &ipv6num, ipv6str, sizeof(ipv6str));
printf("IPv6 주소(다시 변환 후) = %s\n", ipv6str);
return 0;
}
04 (윈도우) IPAddr 예제에서 사용하는 inet_pton() 함수를 모두 WSAStringToAddress() 함수로 변경하시오.
A: WASStringToAddress()는 IP 주소 문자열을 sockaddr_in 구조체로 변환
#include "..\..\Common.h"
int main(int argc, char *argv[])
{
// 윈속 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return 1;
/*----------------*/
/* IPv4 변환 연습 */
/*----------------*/
const char* ipv4test = "147.46.114.70";
printf("IPv4 주소(변환 전) = %s\n", ipv4test);
// WSAStringToAddress() 함수 사용 (inet_pton() 대신)
struct sockaddr_in ipv4num;
int ipv4numSize = sizeof(ipv4num);
WSAStringToAddressA((char*)ipv4test, AF_INET, NULL, (LPSOCKADDR)&ipv4num, &ipv4numSize); // (char*)로 변환
printf("IPv4 주소(변환 후) = %#x\n", ipv4num.sin_addr.s_addr);
/*----------------*/
/* IPv6 변환 연습 */
/*----------------*/
const char* ipv6test = "2001:0230:abcd:ffab:0023:eb00:ffff:1111";
printf("IPv6 주소(변환 전) = %s\n", ipv6test);
// WSAStringToAddress() 함수 사용 (inet_pton() 대신)
struct sockaddr_in6 ipv6num;
int ipv6numSize = sizeof(ipv6num);
WSAStringToAddressA((char*)ipv6test, AF_INET6, NULL, (LPSOCKADDR)&ipv6num, &ipv6numSize); // (char*)로 변환
printf("IPv6 주소(변환 후) = 0x");
for (int i = 0; i < 16; i++)
printf("%02x", ipv6num.sin6_addr.s6_addr[i]);
printf("\n");
// 윈속 종료
WSACleanup();
return 0;
}

05 (윈도우) IPAddr 예제에서 사용하는 inet_ntop() 함수를 모두 WSAAddressToString() 함수로 변경하시오.
A: WASAddressToString()은 sockaddr_in6 구조체를 다시 IPv6 문자열로 변환
#include "..\..\Common.h"
int main(int argc, char *argv[])
{
// 윈속 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0)
return 1;
/*----------------*/
/* IPv4 변환 연습 */
/*----------------*/
const char *ipv4test = "147.46.114.70";
printf("IPv4 주소(변환 전) = %s\n", ipv4test);
struct sockaddr_in ipv4num;
int ipv4numSize = sizeof(ipv4num);
WSAStringToAddress((LPSTR)ipv4test, AF_INET, NULL, (LPSOCKADDR)&ipv4num, &ipv4numSize);
// WSAAddressToString() 함수 사용 (inet_ntop() 대신)
char ipv4str[INET_ADDRSTRLEN];
DWORD ipv4strSize = sizeof(ipv4str);
WSAAddressToString((LPSOCKADDR)&ipv4num, ipv4numSize, NULL, ipv4str, &ipv4strSize);
printf("IPv4 주소(다시 변환 후) = %s\n", ipv4str);
printf("\n");
/*----------------*/
/* IPv6 변환 연습 */
/*----------------*/
const char *ipv6test = "2001:0230:abcd:ffab:0023:eb00:ffff:1111";
printf("IPv6 주소(변환 전) = %s\n", ipv6test);
struct sockaddr_in6 ipv6num;
int ipv6numSize = sizeof(ipv6num);
WSAStringToAddress((LPSTR)ipv6test, AF_INET6, NULL, (LPSOCKADDR)&ipv6num, &ipv6numSize);
// WSAAddressToString() 함수 사용 (inet_ntop() 대신)
char ipv6str[INET6_ADDRSTRLEN];
DWORD ipv6strSize = sizeof(ipv6str);
WSAAddressToString((LPSOCKADDR)&ipv6num, ipv6numSize, NULL, ipv6str, &ipv6strSize);
printf("IPv6 주소(다시 변환 후) = %s\n", ipv6str);
// 윈속 종료
WSACleanup();
return 0;
}
06 도메인 이름을 명령행 인수로 입력받아, 해당 호스트의 모든 별명과 모든 IPv4 주소를 출력하는 프로그램을 작성하시오.
A:
#include "..\..\Common.h"
// 도메인 이름 -> IPv4 주소 및 별명 출력
bool GetIPAddr(const char* name) {
struct hostent* ptr = gethostbyname(name);
if (ptr == NULL) {
printf("gethostbyname() failed\n");
return false;
}
if (ptr->h_addrtype != AF_INET) return false;
// 도메인 이름 출력
printf("Official Name: %s\n", ptr->h_name);
// 별명(aliases) 출력
char** aliases = ptr->h_aliases;
if (*aliases) {
printf("Aliases:\n");
for (int i = 0; aliases[i] != NULL; i++) {
printf(" %s\n", aliases[i]);
}
}
else {
printf("No aliases found.\n");
}
// 모든 IPv4 주소 출력
char** addr_list = ptr->h_addr_list;
printf("IP Addresses:\n");
for (int i = 0; addr_list[i] != NULL; i++) {
struct in_addr* addr = (struct in_addr*)addr_list[i];
char ipstr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, addr, ipstr, sizeof(ipstr));
printf(" %s\n", ipstr);
}
return true;
}
int main(int argc, char* argv[]) {
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
// 명령행 인자 검사
if (argc != 2) {
printf("Usage: %s <domain name>\n", argv[0]);
WSACleanup();
return 1;
}
printf("도메인 이름(변환 전) = %s\n", argv[1]);
// 도메인 이름 -> IP 주소 및 별명 출력
if (GetIPAddr(argv[1])) {
printf("Domain information retrieved successfully.\n");
}
else {
printf("Failed to retrieve domain information.\n");
}
// 윈속 종료
WSACleanup();
return 0;
}



07 IP 주소를 명령행 인수로 입력받아, 해당 호스트의 모든 별명과 모든 IPv4 주소를 출력하는 프 로그램을 작성하시오.
A:
#include "..\..\Common.h"
// IP 주소 -> 도메인 이름 및 별명 출력
void PrintHostInfo(const struct in_addr& addr) {
struct hostent* ptr = gethostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
if (ptr == NULL) {
printf("gethostbyaddr() 실패: %d\n", WSAGetLastError());
return;
}
// 도메인 이름 출력
printf("도메인 이름: %s\n", ptr->h_name);
// 별명(aliases) 출력
char** aliases = ptr->h_aliases;
if (*aliases) {
printf("별명:\n");
for (int i = 0; aliases[i] != NULL; i++) {
printf(" %s\n", aliases[i]);
}
}
else {
printf("별명이 없습니다.\n");
}
// 모든 IPv4 주소 출력
char** addr_list = ptr->h_addr_list;
printf("IPv4 주소:\n");
for (int i = 0; addr_list[i] != NULL; i++) {
struct in_addr* addr_ptr = (struct in_addr*)addr_list[i];
char ipstr[INET_ADDRSTRLEN];
inet_ntop(AF_INET, addr_ptr, ipstr, sizeof(ipstr));
printf(" %s\n", ipstr);
}
}
int main(int argc, char* argv[]) {
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) return 1;
// 명령행 인자 검사
if (argc != 2) {
printf("사용법: %s <IP 주소>\n", argv[0]);
WSACleanup();
return 1;
}
struct in_addr addr;
// IP 주소 변환
if (inet_pton(AF_INET, argv[1], &addr) <= 0) {
printf("유효하지 않은 IP 주소입니다: %s\n", argv[1]);
WSACleanup();
return 1;
}
// IP 주소 -> 도메인 이름 및 별명 출력
PrintHostInfo(addr);
// 윈속 종료
WSACleanup();
return 0;
}

08 NameResolution 예제에서 정의한 GetIPAddr() 함수와 사용법이 같은 GetIPInfo() 함수를 정의하고 테스트하시오. 단, 내부적으로는 getaddrinfo() 함수를 사용하여 도메인 이름에 대응 하는 IPv4 주소를 얻어야 한다.
A:
#include "..\..\Common.h"
// 도메인 이름 -> IPv4 주소
bool GetIPInfo(const char* name, struct in_addr* addr) {
struct addrinfo hints, * result;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; // IPv4
// getaddrinfo 호출
if (getaddrinfo(name, NULL, &hints, &result) != 0) {
printf("getaddrinfo() 실패\n");
return false;
}
// IPv4 주소 가져오기
struct sockaddr_in* ipv4 = (struct sockaddr_in*)result->ai_addr;
memcpy(addr, &ipv4->sin_addr, sizeof(struct in_addr));
freeaddrinfo(result); // 메모리 해제
return true;
}
int main() {
// 소켓 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("WSAStartup() 실패\n");
return 1;
}
struct in_addr addr;
// 도메인 이름에 대한 IP 주소 정보 가져오기
if (GetIPInfo("www.google.com", &addr)) {
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr, str, sizeof(str));
printf("IP 주소: %s\n", str);
}
else {
printf("IP 주소를 가져오는 데 실패했습니다.\n");
}
// 소켓 종료
WSACleanup();
return 0;
}

09 NameResolution 예제에서 정의한 GetDomainName( ) 함수와 사용법이 같은 GetDomainInfo() 함수를 정의하고 테스트하시오. 단. 내부적으로는 getnameinfo() 함수를 사용하여 IPv4 주소에 대응하는 도메인 이름을 얻어야 한다.
A:
#include "..\..\Common.h"
// 도메인 이름 -> IPv4 주소
bool GetIPInfo(const char* name, struct in_addr* addr) {
struct addrinfo hints, * result;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET; // IPv4
// getaddrinfo 호출
if (getaddrinfo(name, NULL, &hints, &result) != 0) {
printf("getaddrinfo() 실패\n");
return false;
}
// IPv4 주소 가져오기
struct sockaddr_in* ipv4 = (struct sockaddr_in*)result->ai_addr;
memcpy(addr, &ipv4->sin_addr, sizeof(struct in_addr));
freeaddrinfo(result); // 메모리 해제
return true;
}
// IPv4 주소 -> 도메인 이름
bool GetDomainInfo(struct in_addr addr, char* name, size_t namelen) {
struct sockaddr_in sa;
sa.sin_family = AF_INET;
sa.sin_addr = addr;
sa.sin_port = 0; // 포트 번호는 사용하지 않음
// getnameinfo 호출
if (getnameinfo((struct sockaddr*)&sa, sizeof(sa), name, namelen, NULL, 0, 0) != 0) {
printf("getnameinfo() 실패\n");
return false;
}
return true;
}
int main() {
// 소켓 초기화
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
printf("WSAStartup() 실패\n");
return 1;
}
struct in_addr addr;
// 도메인 이름에 대한 IP 주소 정보 가져오기
const char* domain_name = "www.google.com";
if (GetIPInfo(domain_name, &addr)) {
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &addr, str, sizeof(str));
printf("IP 주소: %s\n", str);
// IP 주소에 대한 도메인 이름 정보 가져오기
char domain[NI_MAXHOST];
if (GetDomainInfo(addr, domain, sizeof(domain))) {
printf("도메인 이름: %s\n", domain);
}
else {
printf("도메인 이름을 가져오는 데 실패했습니다.\n");
}
}
else {
printf("IP 주소를 가져오는 데 실패했습니다.\n");
}
// 소켓 종료
WSACleanup();
return 0;
}

'네트워크 프로그래밍 > 연습문제' 카테고리의 다른 글
| [네트워크 프로그래밍] 4장 연습문제 (4, 6, 8번) (0) | 2024.11.11 |
|---|---|
| [네트워크 프로그래밍] 2장 연습문제 (0) | 2024.09.20 |
| [네트워크 프로그래밍] 1장 연습문제 (0) | 2024.09.20 |