네트워크 프로그래밍/연습문제

[네트워크 프로그래밍] 4장 연습문제 (4, 6, 8번)

ttttki913 2024. 11. 11. 04:17
TCP/IP 소켓 프로그래밍 2판(한빛아카데미, 2022) 연습문제 풀이

 

Q 4_4. TCPServer/TCPClient 예제를 수정하여, 클라이언트에서 32비트 정수 두 개를 입력받아 보내면 서버에서 두 수의 합을 계산하여 숫자 형태로 리턴하도록 하시오.

 

A: TCPServer.cpp

#include "..\..\Common.h"

#define SERVERPORT 9000
#define BUFSIZE    512

int main(int argc, char *argv[])
{
	..
	// 데이터 통신에 사용할 변수
	..
	// 입력 정수 변수 추가
	int num1 = 0;
	int num2 = 0;

	while (1) {
		..
		while (1) {
			// 데이터 받기
			..

			// 받은 데이터 출력
			..

			// 첫 번째 입력 숫자를 정수로 변환(32비트 정수 - 스페이스 아스키 코드 32까지 정수로)
			num1 = atoi(buf);
			printf("%d ", num1);
			
			// 두 번째 입력 숫자를 정수로 변환(32비트 정수로)
			// 스페이스바 위치를 찾은 후 그 위치부터 반환
			char* ptr = strchr(buf, 32);
			num2 = atoi(ptr);
			printf("%d ", num2);
			
			// num1 + num2 -> 문자열로 변환
			_itoa(num1 + num2, buf, 10);
			
			// 데이터 보내기
			retval = send(client_sock, buf, retval, 0);
			if (retval == SOCKET_ERROR) {
				err_display("send()");
				break;
			}
		}
		..
}

 

 

Q 4_6. TCPServer/TCPClient 예제를 수정하여, 클라이언트에서 32비트 정수 한 개를 입력받아 보내면 서버에서 이 숫자의 이진수 표현을 문자열 형태로 리턴하도록 하시오.

A:

1) TCPServer.cpp

int main(int argc, char* argv[])
{
	..
	// 데이터 통신에 사용할 변수
	..
	int num1 = 0;

	while (1) {
		// accept()
		..
		// 클라이언트와 데이터 통신
		while (1) {
			// 데이터 받기
			..
			// 받은 데이터 출력
			..

			// 첫 번째 입력 숫자를 정수로 변환(32비트 정수 - 스페이스 아스키 코드 32까지 정수로)
			num1 = atoi(buf);
			printf("[서버] 받은 숫자: %d\n", num1);

			// 32비트 정수를 2진수로 변환
			char bin[33];        // 32비트 + NULL 종료 문자
			_itoa(num1, bin, 2); // 정수를 2진수 문자열로 변환

			// 받은 숫자의 이진수 표현 출력
			printf("[서버] %d 의 이진수 표현: %s\n", num1, bin);

			// 이진수 문자열 전송
			retval = send(client_sock, bin, strlen(bin), 0);  // 이진수 전송
			if (retval == SOCKET_ERROR) {
				err_display("send() - 이진수 전송");
				break;
			}
		}
		..
}

 

2) TCPClient.cpp

int main(int argc, char* argv[])
{
	..
	// 데이터 통신에 사용할 변수
	..
	int num;

	// 서버와 데이터 통신
	while (1) {
		// 데이터 입력
		..
		// '\n' 문자 제거
		..

		num = atoi(buf);

		// 데이터 보내기
		retval = send(sock, buf, (int)strlen(buf), 0);
		if (retval == SOCKET_ERROR) {
			err_display("send()");
			break;
		}
		printf("[TCP 클라이언트] %d바이트를 보냈습니다.\n", retval);

		// 데이터 받기 - 2진수 받기로 수정
		retval = recv(sock, buf, BUFSIZE, 0);
		if (retval == SOCKET_ERROR) {
			err_display("recv()");
			break;
		}
		else if (retval == 0)
			break;

		// 받은 데이터 출력
		buf[retval] = '\0';
		printf("[TCP 클라이언트] %d바이트를 받았습니다.\n", retval);
		printf("[받은 데이터] %s\n", buf);
	}
	..
}

 

오른쪽이 client에서 데이터 전송

 

Q 4_8. TCP 클라이언트에서 connect() 함수를 호출하기 전에 bind() 함수를 호출하면 TCP 서버와 마찬가지로 사용할 포트 번호를 고정할 수 있다. TCPClient 예제를 수정하여, 항상 포트 번호 50000을 사용하도록 하시오. 또한 이처럼 구현할 때 어떤 문제가 있을지 논의하시오.

A:(4, 6번 사진 포트 번호 보면 매번 바뀜 이를 50000으로 고정하도록 수정)

- TCPClient.cpp

#include "..\..\Common.h"

char* SERVERIP = (char*)"127.0.0.1";
#define SERVERPORT 9000
#define CLIENTPORT 50000  // 고정 포트 번호 추가
#define BUFSIZE    512

int main(int argc, char* argv[])
{
    int retval;
    ..
    // 클라이언트의 포트 번호 고정 (bind 사용)
    struct sockaddr_in clientaddr;
    memset(&clientaddr, 0, sizeof(clientaddr));
    clientaddr.sin_family = AF_INET;
    clientaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    clientaddr.sin_port = htons(CLIENTPORT);  // 고정 포트 번호

    retval = bind(sock, (struct sockaddr*)&clientaddr, sizeof(clientaddr));
    if (retval == SOCKET_ERROR) {
        err_display("bind()");
        closesocket(sock);
        WSACleanup();
        return 1;
    }

    // 서버 연결
    ..

    // 데이터 통신에 사용할 변수
    ..
    
    .. 
    
    // 소켓 닫기
    ..

    // 윈속 종료
    ..
}

 

 

포트 번호 = 5000

- 포트 번호 고정시 문제점

1) 포트 충돌 가능성

2) 클라이언트와 서버 간 포트 번호 조정 필요

3) NAT 및 방화벽 문제 발생 가능