티스토리 뷰

원래 코드에 호스트이름을 입력하면 호스트의 IP주소들을 얻어서 출력하는 형식또한 추가하였습니다.

 

클라코드

더보기
//Client
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include "resource.h"

#define SERVERIP "127.0.0.1"
#define SERVERPORT 9000
#define BUFSIZE 512


//윈도우 프로시저
BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM);
//편집 함수
void DisplayText(const char* fmt, ...);
//오류 출력 함수
void err_quit(const char* msg);

//사용자 정의 데이터 수신 함수
int recvn(SOCKET s, char* buf, int len, int flags);
//소켓 통신 스레드 함수
DWORD WINAPI ClientMain(LPVOID arg);

SOCKET sock;
char buf[BUFSIZE + 1];
int check = 0;   // 데이터 전송인지, IP 전송인지 전달
HANDLE hReadEvent, hWriteEvent;
HWND hSendButton, hIPButton;
HWND hEdit1, hEdit2;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
	...
}

BOOL CALLBACK DlgProc(HWND hDlg, UINT uMsg, WPARAM wParm, LPARAM lParm) {
	...
	case WM_COMMAND:
		switch (LOWORD(wParm)) {
		case IDOK:
			EnableWindow(hSendButton, FALSE);
			WaitForSingleObject(hReadEvent, INFINITE);
			check = 1;
			GetDlgItemText(hDlg, IDC_EDIT1, buf, BUFSIZE + 1);
			SetEvent(hWriteEvent);
			SetFocus(hEdit1);
			SendMessage(hEdit1, EM_SETSEL, 0, -1);
			return TRUE;
		case IDSEND:
			EnableWindow(hIPButton, FALSE);
			WaitForSingleObject(hIPButton, INFINITE);
			check = 0;
			GetDlgItemText(hDlg, IDC_EDIT1, buf, BUFSIZE + 1);
			SetEvent(hWriteEvent);
			SetFocus(hEdit1);
			return TRUE;
		case IDCANCEL:
			EndDialog(hDlg, IDCANCEL);
			return TRUE;
		}
		return FALSE;
	}
	return FALSE;
}


// 편집 컨트롤 출력 함수
void DisplayText(const char* fmt, ...) {
	...
}

void err_quit(const char* msg) {
	...
}

int recvn(SOCKET s, char* buf, int len, int flag) {
	...
}
DWORD WINAPI ClientMain(LPVOID arg) {
	...

	while (1) {
		WaitForSingleObject(hWriteEvent, INFINITE);

		//문자열 길이가 0이면 보내지 않음
		if (strlen(buf) == 0) {
			EnableWindow(hSendButton, TRUE);
			SetEvent(hReadEvent);
			continue;
		}

		//데이터 전달인지, 호스트 이름 전달인지 형태 전달하기
		retVal = send(sock, (char*)&check, sizeof(int), 0);
		if (retVal == SOCKET_ERROR) {
			err_quit("Send()");
			break;
		}

		//데이터 보내기 
		retVal = send(sock, buf, strlen(buf), 0);
		if (retVal == SOCKET_ERROR) {
			err_quit("Send()");
			break;
		}

		DisplayText("[TCP 클라이언트] %d바이트를 보냈습니다.\r\n", retVal);

		if (check) {
			retVal = recvn(sock, buf, retVal, 0);
			if (retVal == SOCKET_ERROR) {
				err_quit("recv()");
				break;
			}
			else if (retVal == 0)
				break;

			//받은 데이터 출력
			buf[retVal] = '\0';
			DisplayText("[TCP 클라이언트] : %d바이트를 받았습니다.\r\n", retVal);
			DisplayText("[받은 데이터] : %s\r\n", buf);
			EnableWindow(hSendButton, TRUE);
		}
		else {
			DisplayText("%s의 호스트 내역\r\n", buf);
			short count = 0;
			IN_ADDR addr = { 0, };
			while (retVal != 0) {
				retVal = recv(sock, (char*)&count, sizeof(short), 0);
				if (retVal == SOCKET_ERROR) {
					err_quit("Recv()");
					break;
				}
				else if (count == 0)
					break;
				DisplayText("%d ", count);
				retVal = recv(sock, (char*)&addr, sizeof(IN_ADDR), 0);
				if (retVal == SOCKET_ERROR) {
					err_quit("Recv()");
					break;
				}
				DisplayText("IP주소 : %s\r\n", inet_ntoa(addr));
			}
			EnableWindow(hIPButton, TRUE);
		}	
		SetEvent(hReadEvent);
	}
	
	return 0;
}

서버코드

더보기
//Server
#pragma comment(lib, "ws2_32")
#pragma warning(disable:4996)
#include<WinSock2.h>
#include<stdlib.h>
#include<Windows.h>
#include<stdio.h>

#define SERVERPORT 9000
#define BUFSIZE 512

//윈도우 프로시저
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParm, LPARAM lParm);

//편집 컨트롤 출력 함수
void DisplayText(const char* fmt, ...);

//오류 출력 함수
void err_quit(const char* msg);

//소켓 통신 함수
DWORD WINAPI ServerMain(LPVOID arg);
DWORD WINAPI ProcessClient(LPVOID arg);

HINSTANCE hInst;		// 인스턴스 핸들
HWND hEdit;				// 편집 컨트롤
CRITICAL_SECTION cs;	// 임계영역

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
...
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParm, LPARAM lParm) {
	...
}

// 편집 컨트롤 출력 함수
void DisplayText(const char* fmt, ...) {
	...
}
void err_quit(const char* msg) {
	...
}

DWORD WINAPI ServerMain(LPVOID arg) {
	...
}
DWORD WINAPI ProcessClient(LPVOID arg) {
	SOCKET clientfd = (SOCKET)arg;
	SOCKADDR_IN clientaddr;
	int addrlen;
	int len, check, retVal;
	char buf[BUFSIZE + 1];

	//클라 정보 얻기
	addrlen = sizeof(clientaddr);
	getpeername(clientfd, (SOCKADDR*)&clientaddr, &addrlen);

	while (1) {
		//형태 전달받기
		retVal = recv(clientfd, (char*)&check, sizeof(int), 0);

		if (check) {
			//데이터받기(고정길이)
			retVal = recv(clientfd, buf, BUFSIZE, 0);
			if (retVal == SOCKET_ERROR) {
				err_quit("Recv");
				break;
			}
			else if (retVal == 0) break;

			//받은 데이터 출력
			buf[retVal] = '\0';
			DisplayText("[TCP/%s : %d] %s\r\n", inet_ntoa(clientaddr.sin_addr),
				ntohs(clientaddr.sin_port), buf);

			retVal = send(clientfd, buf, retVal, 0);
			if (retVal == SOCKET_ERROR) {
				err_quit("Send");
				break;
			}
		}
		else {
			//데이터받기(고정길이)
			retVal = recv(clientfd, buf, BUFSIZE, 0);
			if (retVal == SOCKET_ERROR) {
				err_quit("Recv");
				break;
			}
			else if (retVal == 0) break;
			buf[retVal] = '\0';
			DisplayText("[TCP IP 호스트 이름 ] : %s\r\n", buf);

			//로컬 호스트 얻어오기
			IN_ADDR addr = { 0, };
			HOSTENT* ptr = gethostbyname(buf);//호스트 엔트리 얻어오기		
			while (ptr && ptr->h_name)
			{
				if (ptr->h_addrtype == PF_INET)//IPv4 주소 타입일 때
				{
					for (int index = 0; ptr->h_addr_list[index]; index++)
					{
						send(clientfd, (char*)&ptr->h_length, sizeof(short), 0);
						memcpy(&addr, ptr->h_addr_list[index], ptr->h_length);//메모리 복사
						send(clientfd, (char*)&addr, sizeof(IN_ADDR), 0);
					}
				}
				ptr++;
			}
			short index = 0;
			send(clientfd, (char*)&index, sizeof(short), 0);
		}
	}
	closesocket(clientfd);
	DisplayText("[TCP 서버] 클라이언트 종료 : IP  주소 = %s, 포트번호 = %d\r\n",
		inet_ntoa(clientaddr.sin_addr), ntohs(clientaddr.sin_port));

	return 0;
}
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함