티스토리 뷰
원래 코드에 호스트이름을 입력하면 호스트의 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;
}
'서버 공부 > 네트워크' 카테고리의 다른 글
이상적인 소켓 입출력 모델의 특징 (0) | 2022.07.08 |
---|---|
비동기 형식 TCP/IP 서버 (0) | 2022.07.08 |
GUI 멀티쓰레드 소켓 프로그래밍(TCP) (0) | 2022.07.07 |
TCP/IP 윈도우 소켓 프로그래밍 7장 연습문제 (0) | 2022.07.05 |
멀티 쓰레드를 활용한 서버/클라이언트 기본 통신 (0) | 2022.07.05 |
댓글