728x90
SMALL
- 설명 -
프로젝트 명 : ChatServer(대화 상자)
① CSocket 클래스 이용 : 동기식(블로킹)으로 동작
② 서버 클라이언트 1:1 통신
③ 해당 글은 서버용 채팅 프로그램 만드는 법 설명
1. MFC 애플리케이션 옵션 설정
① 애플리케이션 종류 : 대화 상자
② [고급 기능] → [Windows 소켓] 활성화
2. 다이얼로그 디자인 및 ID
3. CSocket 기반의 CSocServer, CSocCom MFC 클래스 생성
① [프로젝트] → [클래스 마법사] → [클래스 추가] 버튼 옆의 ▼ 버튼 → [MFC 클래스] 선택 → 클래스 생성
② CSocServer : 서버용 소켓
③ CSocCom : 통신용 소켓
4. CSocServer, CSocCom MFC 클래스에 가상 함수 추가
① OnAccept(CSocServer) : 클라이언트 접속 요청 처리
② OnReceive(CSocCom) : 데이터가 도착했다는 것을 알려줌
5. stdAfx.h 헤더 파일 생성
① CSocServer, CSocCom 헤더 파일 include
② 사용자 정의 메시지 선언
- UM_ACCEPT : 메인 윈도우에 메시지를 보내기 위한 구별자. 즉, 메인 윈도우(여기서는 m_hWnd)에
SendMessage를 이용해 UM_ACCEPT라는 사용자 정의 메시지를 줌.
- UM_RECEIVE : UM_ACCEPT와 비슷한 역할.
- stdAfx.h 소스 보기
더보기
#pragma once
#include <afxsock.h> // 소켓 클래스 사용 위해 include
#include "SocServer.h" // 서버용 소켓
#include "SocCom.h" // 통신용 소켓
#define UM_ACCEPT WM_USER+1 // 메인 윈도우에 메시지를 보내기 위한 구별자. 즉, 메인 윈도우(여기서는 m_hWnd)에 SendMessage를 이용해 UM_ACCEPT라는 사용자 정의 메시지를 줌.
#define UM_RECEIVE WM_USER+2 // UM_ACCEPT와 비슷한 역할
6. CSocCom 클래스 작업
① HWND m_hWnd : 메인 윈도우 핸들
② Init() : 소켓 클래스와 메인 윈도우를 연결시킴
③ OnReceive() : 데이터가 도착했다는 것을 알려줌
- SocCom.h 소스 보기
더보기
#pragma once
// CSocCom 명령 대상
// 통신용 소켓
#define UM_RECEIVE WM_USER+2
class CSocCom : public CSocket
{
public:
CSocCom();
virtual ~CSocCom();
HWND m_hWnd; // 메인 윈도우 핸들
void CSocCom::Init(HWND hWnd); // 소켓 클래스와 메인 윈도우를 연결시킴
virtual void OnReceive(int nErrorCode); // 데이터가 도착했다는 것을 알려줌
};
- SocCom.cpp 소스 보기
더보기
// CSocCom 멤버 함수
// 소켓 클래스와 메인 윈도우를 연결시킴
void CSocCom::Init(HWND hWnd) {
m_hWnd = hWnd;
}
// 데이터가 도착했다는 것을 알려주는 가상 함수
void CSocCom::OnReceive(int nErrorCode)
{
// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
SendMessage(m_hWnd, UM_RECEIVE, 0, 0);
CSocket::OnReceive(nErrorCode);
}
SMALL
7. CSocServer 클래스 작업
① HWND m_hWnd : 메인 윈도우 핸들
② CSocCom m_socCom : 연결 요청을 한 클라이언트 서버와 실제 연결이 되는 소켓
③ Init() : 소켓 클래스와 메인 윈도우를 연결시킴
④ OnAccept() : 클라이언트 접속 요청 처리
⑤ GetAcceptSocCom() : 통신 소켓 리턴
- SocServer.h 소스 보기
더보기
#pragma once
#include "SocCom.h"
#define UM_ACCEPT WM_USER+1
// CSocServer 명령 대상
// 서버용 소켓
class CSocServer : public CSocket
{
public:
CSocServer();
virtual ~CSocServer();
CSocCom m_socCom; // 연결 요청을 한 클라이언트 서버와 실제 연결이 되는 소켓
CSocCom* GetAcceptSocCom(); // 통신 소켓 리턴
HWND m_hWnd; // 메인 윈도우 핸들
void CSocServer::Init(HWND hWnd); // 소켓 클래스와 메인 윈도우를 연결시킴
virtual void OnAccept(int nErrorCode); // 클라이언트 접속 요청 처리
};
- SocServer.cpp 소스 보기
더보기
// CSocServer 멤버 함수
// 소켓 클래스에서는 소켓의 메시지(On으로 시작하는 함수)만을 처리하고, 실제 동작은 메인 프로그램에서 수행
// 소켓 클래스와 메인 윈도우를 연결시키는 것이 필요 → Init 함수
void CSocServer::Init(HWND hWnd) {
// 메인 윈도우 포인터 받기
m_hWnd = hWnd;
}
// 클라이언트에서 접속 요청이 올 경우 OnAccept 함수가 호출됨
// OnAccept 함수가 호출되면 접속 요청할 한 소켓과 다른 소켓을 연결하기 위해 Accept 함수를 호출한 뒤 메인 윈도우에 OnAccept 함수가 호출되었다는 것을 알려줌
void CSocServer::OnAccept(int nErrorCode)
{
// TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
Accept(m_socCom); // m_socCom은 연결 요청을 한 클라이언트 서버와 실제 연결이 되는 소켓
SendMessage(m_hWnd, UM_ACCEPT, 0, 0);
CSocket::OnAccept(nErrorCode);
}
// 메인 윈도우에서는 m_socCom을 얻어서 통신을 처리
CSocCom* CSocServer::GetAcceptSocCom() {
// 통신소켓을 return
// 반환되는 통신 소켓은 클라이언트와 연결됨
return &m_socCom;
}
8. ChatServerDlg에 서버용 소켓, 통신용 소켓 선언 및 OnInitDialog 메시지 함수 코딩
① CSocServer m_socServer : 서버용 소켓
② CSocCom* m_socCom : 통신용 소켓
③ OnInitDialog : 클라이언트 접속 기다리는 코드 추가(포트번호 5000)
- 소스 보기
더보기
// TODO: 여기에 추가 초기화 작업을 추가합니다.
m_socCom = NULL;
// 서버 소켓을 생성(포트번호 5000)
m_socServer.Create(5000);
// 클라이언트의 접속을 기다림
m_socServer.Listen();
// 소켓 클래스와 메인 윈도우(여기에서는 CChatServerDlg)를 연결
m_socServer.Init(this->m_hWnd);
9. ChatServerDlg에 메시지 함수 추가
① OnAccept() : 클라이언트 접속 요청이 왔을때 실제 접속은 CSocServer 클래스의 OnAccept()에서 처리하고, 접속한 소켓은 GetAcceptSocCom을 이용해 얻어옴.
② OnReceive() : 소켓 연결 이후 모든 통신을 해당 메시지 함수를 이용함.
- 그림 14, 그림 15의 소스 보기
더보기
// ChatServerDlg.h
afx_msg LPARAM OnAccept(UINT wParam, LPARAM lParam); // 클라이언트 접속 요청이 왔을 때 실행되는 메세지 함수
afx_msg LPARAM OnReceive(UINT wParam, LPARAM lParam); // 클라이언트에서 오는 데이터 수신할때 실행되는 메세지 함수
// ChatSeverDlg.cpp - MESSAGE_MAP PART
ON_MESSAGE(UM_ACCEPT, OnAccept)
ON_MESSAGE(UM_RECEIVE, OnReceive)
- OnAccept(), OnReceive() 소스 보기
더보기
// 클라이언트 연결 요청이 왔기 때문에 Accept 함수로 접속
// 실제 접속을 담당하는 것은 CSocServer
// 이렇게 접속한 소켓은 GetAcceptSocCom을 이용해 얻어옴
// OnAccept 실행 이후 서버용 소켓인 m_socServer의 역활은 끝나고, 실제 모든 통신은 통신용 소켓인 m_socCom을 이용
LPARAM CChatServerDlg::OnAccept(UINT wParam, LPARAM lParam) {
// 클라이언트에서 접속 요청이 왔을 때
m_strStatus = "접속성공";
// 통신용 소켓을 생선한 뒤
m_socCom = new CSocCom;
// 서버소켓과 통신소켓을 연결한다.
m_socCom = m_socServer.GetAcceptSocCom();
m_socCom->Init(this->m_hWnd);
m_socCom->Send("접속성공", 256); // 소켓이 연결되었다는 것을 클라이언트에 알리기 위해 Send 함수로“접속성공”이라는 문자열을 보냄
UpdateData(FALSE);
return TRUE;
}
// 데이터를 보내는 것은 소켓 클래스의 멤버 함수인 Send를 이용
// 데이터를 받을 때는 통신 소켓 클래스에 오버라이딩한 OnReceive 메시지 함수를 사용
LPARAM CChatServerDlg::OnReceive(UINT wParam, LPARAM lParam) {
// 접속된 곳에서 데이터가 도착했을 때
char pTmp[256];
CString strTmp;
memset(pTmp, '\0', 256);
// 데이터를 pTmp에 받는다.
m_socCom->Receive(pTmp, 256);
strTmp.Format("%s", pTmp);
// 리스트박스에 보여준다.
int i = m_list.GetCount();
m_list.InsertString(i, strTmp);
return TRUE;
}
10. [전송] 버튼 클릭 메시지 함수 작업
① [전송] 버튼 클릭 시 클라이언트에게 데이터 전송
② IDC_BUTTON_SEND의 메시지 함수
- 메시지 함수 소스 보기
더보기
// [전송] 버튼을 클릭했을 때
void CChatServerDlg::OnClickedButtonSend()
{
// TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
UpdateData(TRUE);
char pTmp[256];
CString strTmp;
// pTmp에 전송할 데이터 입력
memset(pTmp, '\0', 256);
strcpy_s(pTmp, m_strSend);
m_strSend = "";
// 전송
m_socCom->Send(pTmp, 256);
// 전송한 데이터도 리스트박스에 보여준다.
strTmp.Format("%s", pTmp);
int i = m_list.GetCount();
m_list.InsertString(i, strTmp);
UpdateData(FALSE);
}
11. 실행화면
관련글
728x90
LIST
'C++ > MFC' 카테고리의 다른 글
[MFC] 채팅 프로그램 - 다중접속(멀티) (3/3) (0) | 2021.08.26 |
---|---|
[MFC] 채팅 프로그램 - 클라이언트 (2/3) (6) | 2021.08.26 |
[MFC] 그림 그리기(그림판) (0) | 2021.08.24 |
[MFC] 메모장(에디터 프로그램) (0) | 2021.08.24 |
[MFC] 파일 및 폴더 검색기 (2) | 2021.08.23 |