소켓실습을 위한 프로젝트 만들기(프로젝트이름: CChatServer)
1. MFC클래스 추가(클래스이름: CSocServer, 기본클래스: CSocket)-연결을 담당하는 클래스
1.1 CChatServerDlg클래스가 CSocServer클래스를 이용할 수 있게 하기
//////////////////////////////////////////////////////////////////////////////////
//////
////// 다른 클래스의 데이터 받아 이용하려면,
//////
////// 1. 헤더파일 추가
////// 이용하려는 클래스에서 이용할 클래스의 헤퍼파일을 #include로 추가해주고,
//////
////// 2. 객체 생성
////// 같은 곳에 객체를 만들어 준다.(동적할당)
//////
//////////////////////////////////////////////////////////////////////////////////
ChatServerDlg.h에 #include "SocServer.h" 추가
CSocServer.h에서 속성-재정의 OnAccept // 소켓함수 재정의 OnAccept: 클라리언트로 부터 오는 접속 요청을 처리하는 함수
CSocServer.h에 Accept(); 추가
CSocServer.h에 SendMessage(m_hWnd, UM_ACCEPT, 0, 0); 추가
2. CSocket클래스 에서도 CCharServerDlg클래스를 이용할 수 있게 하기위해
윈도우 핸들값을 가져온다.
SocServer.cpp에
void CSocServer::InitHwnd()
{
m_hWnd = hWnd;
};
ChatServerDlg.cpp의 메시지맵에 On_MESSAGE(UM_ACCEPT, ONAccept) 등록
ChatServerDlg.h에 afx_msg LPARAM OnAccept(UINT wPara, LPARAM lParam); 등록
stdafx.h의 상단에 #define UM_ACCEPT WM_USER+1 추가
3. MFC클래스 추가(클래스이름: CSocCom, 기본클래스: CSocket)
-데이터 송수신 담당(소켓서버는 연결 담당)
3.1 ChatServerDlg.h에 CSocCom m_socCom; 추가
3.2 SocCom.h에
public:
HWND m_hWnd;
void InitHwnd(HWND hWnd);추가
3.3 ChatServerDlg.h에 #include "SocCom.h" 추가
3.4 SocCom.cpp에,
void CSocCom::InitHwnd()
{
m_hWnd = hWnd;
};
4. SocCom.cpp에서 OnReceive 함수 재정의
SendMessage(m_hWnd, UM_RECEIVE, 0,0); // 클라이언트 데이터가 도착했다는 것을 알려준다.
5. stdafx.h에 #define UM_RECERVE WM_USER+2 추가
// 기본셋팅
이제 프로그램 작성.
1. 소켓 생성
ChatServerDlg.cpp의 OnInitDialog()함수에서 소켓을 만들어 준다.
m_socCom = NULL;
m_socServer.Create(8000); // 소켓을 생성(포트번호 8000번)
m_socServer.Listen(); // 클라이언트가 접속해오길 기다린다(스레드)
m_socServer.InitHwnd(this->m_hWnd); //소켓클래스와 메인 윈도우를 연결
(자기자신의 클래스에서(this) m_hWnd핸들을 socServer에서 가져오는 것??)
포트번호: 데이터 통신을 하기 위한 게이트. 상대방도 포트번호가 같아야 통신이 가능함. 양쪽이 같게 세팅해야 함.
2. 객체 바인딩
2.1 ChatServerDlg.cpp에
LPARAM CChatServerDlg::OnAccept(UNIT wParam, LPARAM lParam)
{
// 클라이언트에서 접속요청이 왔을 때
m_strStatus = "접속성공";
}
2.2 ChatServerDlg.h에 (아래 세줄 추가)
public:
CSocServer m_socServer;
CSocCom m_socCom;
CString m_strSend;
CString m_strStatus;
CListBox m_list;
2.3 다시 ChatServerDlg.cpp에 다음과 같이 작성한다.
LPARAM CChatServerDlg::OnAccept(UNIT wParam, LPARAM lParam)
{
// 클라이언트에서 접속요청이 왔을 때
m_strStatus = "접속성공";
// 통신용소켓을 생성한다.
m_socCom = new CSocCom;
//서버소켓과 통신소켓을 각각 연결한다.
m_socCom = m_socServer_GetAcceptSocCom();
m_socCom->InitHwnd(this->m_hWnd);
m_socCom->Send("접속성공!!!", 256);
UpdateData(FALSE);
return TRUE;
}
2.4 SocServer.h에 GetAcceptSocCom()함수 선언
CSocCom* GetAcceptSocCom();
2.5 SocServer.cpp에서 구현
CSocCom*CSocServer::GetAcceptSocCom()
{
return &m_socCom;
}
2.6 ChatServerDlg.h에 afx_msg LPARAM OnReceive(UINT wParam, LPARAM lParam); 추가
2.7 ChatServerDlg.cpp에서 메시지 처리 함수 작성
LPARAM CChatServerDlg::OnReceive(UNIT wParam, LPARAM lParam)
{
char pTmp(256);
CString strTmp;
memset(pTmp, '\0', 256);
m_socCom->Receive(pTmp,256);
strTmp.Format("%s",pTmp); //버퍼에 메시지 저장
int i = m_listGetCount();
m_list.InsertString(i, srtTmp); //리스트박스에 출력
return TRUE;
}
2.8 ChatServerDlg.cpp에서 메시지맵에 추가
ON_MESSAGE(UM_RECEIVE, OnReceive)
2.9 CSocCom과 CSocServer간 통신이 안되는 문제점을 해결하기 위해
SocServer.cpp에 Accept()함수의 매개변수 추가. Accept(m_socCom);
SocServer.h에 선언 CSocCom m_socCom;
3. SendButton 더블클릭하여 아래 코드 추가
void CChatServerDlg::OnBnClickedButtonSend()
{
UpdateData(TRUE);
char pTmp[256];
CString strTmp;
// pTmp에 전송할 데이터를 담는다.
memset(pTmp, '\0', 256);
strcpy(pTmp, m_strSend); //전송
m_socCom->Send(pTmp, 256);
//전송한 데이터도 리스트박스에 보여준다.
strTmp.Format("%s", pTmp);
int i = m_list.GetCount();
m_list.InsertString(i, strTmp);
}
// 이후과정은 못적음........
OnReceive()함수가 실행되는 시점
→ 파라미터 값을 보면 알 수 있다.
OnCreate()함수가 실행되는 시점
→ UM_RECEIVE메시지가 메시지 큐에 쌓이면 실행됨
실제 화면출력만 ChatServerDlg.cpp에서 하고,
신호를 받고 보내고 메시지를 보내고 받는것(실제 처리)은 SocServer와 SocCom에서 나눠서 함.