본문 바로가기

Programming Language/C&C++

소켓 통신 #2 - AF_INET 사용하기 (3)

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

소켓 통신 #2 - AF_INET 사용하기 (3)

- by Tapito


소켓을 사용하기 위해 서버와 클라이언트 모두 각 단계별로 실행할 함수에 대해 알아보았습니다. 이를 종합하여 완성된 소스는 다음과 같습니다. Linux/Unix 에서는 잘 작동 될 것이라 생각되지만, Windows 사용자는 잘 작동이 안될 수 있습니다. WinSock이라는 약간 다른 함수를 사용하기 때문입니다.

/* server.c */
int main(int argc, char * argv[])
{
	/* 자기 자신의 포트와 IP 주소 */
	struct sockaddr_in sockaddrServer;
	/* sockaddrServer 구조체 인스턴스의 크기 */
	int sockaddrServerLength = sizeof(sockaddr_in);
	/* 자기 자신의 서버용 소켓 */
	SOCKET sockServer;

	/* 자신에게 접속해 온 클라이언트의 포트와 IP 주소 */
	struct sockaddr_in sockaddrClient;
	/* sockaddr */
	int sockaddrClientLength = 0;
	/* 클라이언트로부터 얻은 소켓 */
	SOCKET sockClient;

	/* 소켓 함수 실행 결과 */
	int status;

	/* -------- 1 단계 -------- */
	/* sockaddr_in 구조체를 사용하기 전에 항상 구조체의 모든 내용을 0으로 초기화합니다. */
	memset(&sockaddrServer, 0, sizeof(struct sockaddr_in));
	/* 인터넷 망에 접속 */
	sockaddrServer.sin_family = AF_INET;
	/* 서버이므로 접속 대상이 없음 */
	sockaddrServer.sin_addr.s_addr = htonl(INADDR_ANY);
	/* 포트 번호는 1435로 */
	sockaddrServer.sin_port = htons((u_short)1435);

	/* -------- 2 단계 -------- */
	printf("creating socket...\n");
	/* 인터넷망에 접속하며 스트림 방식으로 데이터를 교환하는 소켓 생성 */
	sockServer = socket(AF_INET, SOCK_STREAM, 0);
	if (sockServer == INVALID_SOCKET)
	{
		printf("Invalid Socket in step 2\n");
		return -1;
	}
	printf("socket created.\n");

	/* -------- 3 단계 -------- */
	printf("binding...\n");
	/* sockaddr_in 구조체와 생성한 소켓을 연결하여 서버용 소켓으로 이용함 */
	status = bind(sockServer, (struct sockaddr *)&sockaddrServer, sizeof(struct sockaddr_in));
	if (status == SOCKET_ERROR)
	{
		printf("Socket Error in step 3\n");
		return -1;
	}
	printf("bound.\n");

	/* -------- 4 단계 -------- */
	printf("listening...\n");
	/* 연결 대기 상태로 만들기 */
	status = listen(sockServer, 5);
	if (status == SOCKET_ERROR)
	{
		printf("Socket Error in step 4\n");
		closesocket(sockServer); // 오류 시 서버용 소켓 닫기
		return -1;
	}
	printf("listened. %d\n", WSAGetLastError());

	/* -------- 5 단계 -------- */
	/* 클라이언트로부터 넘어오는 sockaddr_in 구조체도 마찬가지로 사용 전 0으로 초기화 */
	memset(&sockaddrClient, 0, sizeof(struct sockaddr_in));
	sockaddrClientLength = sizeof(struct sockaddr_in);
	/* 접속을 요청한 1명의 소켓 얻기 */
	sockClient = accept(sockServer, (struct sockaddr *)&sockaddrClient, &sockaddrClientLength);
	if (sockClient == INVALID_SOCKET)
	{
		printf("Invalid Socket in step 5\n");
		closesocket(sockServer); // 오류 시 서버용 소켓 닫기
		return -1;
	}

	/* 접속자 정보 확인 */
	printf("Accessed from %s:%d (sockaddr = %d bytes)\n", inet_ntoa(sockaddrClient.sin_addr), (int)ntohs(sockaddrClient.sin_port), sockaddrClientLength);

	/* 클라이언트와 서버 소켓 순으로 닫고 프로그램 종료 */
	closesocket(sockClient);
	closesocket(sockServer);

	return 0;
}

 

한편 클라이언트용 소켓은

/* client.c */
int main(int argc, char * argv[])
{
	/* 접속 대상의 포트와 IP 주소 */
	struct sockaddr_in sockaddrServer;
	/* sockaddrServer 구조체 인스턴스의 크기 */
	int sockaddrServerLength = sizeof(sockaddr_in);

	/* 서버에 접속할 용도로 만든 소켓 */
	SOCKET sockServer;
	/* 소켓 함수 실행 결과 */
	int status;

	/* -------- 1 단계 -------- */
	memset(&sockaddrServer, 0, sockaddrServerLength);
	sockaddrServer.sin_family = AF_INET;
	sockaddrServer.sin_addr.s_addr = inet_addr("127.0.0.1");
	sockaddrServer.sin_port = htons((u_short)1435);

	/* -------- 2 단계 -------- */
	sockServer = socket(AF_INET, SOCK_STREAM, 0);
	if (sockServer == INVALID_SOCKET)
	{
		printf("Invalid Socket in step 2\n");
		closesocket(sockServer);
		return -1;
	}

	/* -------- 3 단계 -------- */
	status = connect(sockServer, (struct sockaddr *)&sockaddrServer, sizeof(struct sockaddr_in));
	if (status == SOCKET_ERROR)
	{
		printf("Socket Error in step 3\n");
		closesocket(sockServer);
		return -1;
	}

	closesocket(sockServer);

	return 0;
}