More actions
imported>Unknown No edit summary |
(Repair batch-0001 pages from live compare) |
||
| Line 38: | Line 38: | ||
=== 예제(서버) === | === 예제(서버) === | ||
Dialog based -> Windows Sockets를 설정 | |||
기초 클래스가 CAsyncSocket인 새로운 클래스 CListenSock, CChildSock을 새로 생성한다. | 기초 클래스가 CAsyncSocket인 새로운 클래스 CListenSock, CChildSock을 새로 생성한다. | ||
| Line 44: | Line 44: | ||
새로 추가된 두개의 클래스를 다음과 같이 편집한다. | 새로 추가된 두개의 클래스를 다음과 같이 편집한다. | ||
클래스위저드의 CListenSock에 가상 함수 OnAccept()를 추가한 후 다음 라인을 삽입한다. | |||
((CServerApp*)AfxGetApp())->Accept(); | ((CServerApp*)AfxGetApp())->Accept(); | ||
클래스위저드의 CChildSock에 가상 함수 OnReceive()와 OnClose()를 추가한 후 다음 코드를 삽입한다. | |||
((CServerApp*)AfxGetApp())->CloseChild(); | ((CServerApp*)AfxGetApp())->CloseChild(); | ||
((CServerApp*)AfxGetApp())->ReceiveData(); | ((CServerApp*)AfxGetApp())->ReceiveData(); | ||
| Line 88: | Line 88: | ||
UINT nPort; | UINT nPort; | ||
m_pChild->GetSockName(strText, nPort); | m_pChild->GetSockName(strText, nPort); | ||
strText = " | strText = "[" + strText + "]" + strData; | ||
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ||
} | } | ||
| Line 94: | Line 94: | ||
void CServerApp::ReceiveData() | void CServerApp::ReceiveData() | ||
{ | { | ||
char temp | char temp[1000]; | ||
m_pChild->Receive(temp, sizeof(temp)); | m_pChild->Receive(temp, sizeof(temp)); | ||
| Line 100: | Line 100: | ||
UINT nPort; | UINT nPort; | ||
m_pChild->GetPeerName(strText, nPort); | m_pChild->GetPeerName(strText, nPort); | ||
strText = " | strText = "[" + strText + "]" + temp; | ||
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ||
} | } | ||
| Line 121: | Line 121: | ||
} | } | ||
리소스뷰에서 다이얼로그 항목의 "IDD_SERVER_DIALOG"을 편집한다. | |||
리스트박스ID : IDC_LIST1 | 리스트박스ID : IDC_LIST1 | ||
에디트 컨트롤ID : IDC_DATA | 에디트 컨트롤ID : IDC_DATA | ||
| Line 128: | Line 128: | ||
((CServerApp*)AfxGetApp)->InitServer(); | ((CServerApp*)AfxGetApp)->InitServer(); | ||
GetDlgItem(IDC_SEND)->EnableWindow(FALSE); | GetDlgItem(IDC_SEND)->EnableWindow(FALSE); | ||
그리고 나서 | 그리고 나서 클래스위저드의 CServerDlg에 IDC_SEND를 맵핑한 후 다음 코드를 추가한다. | ||
CString strData; | CString strData; | ||
GetDlgItemText(IDC_DATA, strData); | GetDlgItemText(IDC_DATA, strData); | ||
| Line 136: | Line 136: | ||
=== 예제(클라이언트) === | === 예제(클라이언트) === | ||
서버와 동일한 방법으로 클라이언트 프로그램에서 사용할 소켓 클래스 CClientSock을 생성(기초 클래스: CAsyncSocket)한다. 그리고 나서 | 서버와 동일한 방법으로 클라이언트 프로그램에서 사용할 소켓 클래스 CClientSock을 생성(기초 클래스: CAsyncSocket)한다. 그리고 나서 클래스위저드의 CClientSock에 가상함수 OnReceive()와 OnClose()를 추가한 후, 다음 코드를 삽입한다. | ||
((CClientApp*)AfxGetApp())->CloseChild(); | ((CClientApp*)AfxGetApp())->CloseChild(); | ||
((CClientApp*)AfxGetApp())->ReceiveData(); | ((CClientApp*)AfxGetApp())->ReceiveData(); | ||
서버 접속시 필요한 IP 주소를 입력받기 위해 | 서버 접속시 필요한 IP 주소를 입력받기 위해 리소스뷰에서 다이얼로그를 하나 추가한 후 다음과 같이 편집한다. | ||
IP주소 컨트롤ID : IDC_IPADDRESS1 | IP주소 컨트롤ID : IDC_IPADDRESS1 | ||
버튼 ID : IDOK, IDCANCLE | 버튼 ID : IDOK, IDCANCLE | ||
클래스위저드를 실행하여 CConnectDlg 클래스를 새로 생성한 후 CConnectDlg 클래스에 다음 변수를 추가한다. | |||
CString m_strAddress; | CString m_strAddress; | ||
그리고 | 그리고 클래스위저드의 CConnectDlg에 IDOK를 맵핑하여 사용자가 입력한 IP 주소를 멤버변수 m_strAddress에 저장한다. | ||
GetDlgItemText(IDC_IPADDRESS1, m_strAddress); | GetDlgItemText(IDC_IPADDRESS1, m_strAddress); | ||
어플리케이션 클래스에 다음과 같이 멤버변수와 함수 원형을 선언한다. | 어플리케이션 클래스에 다음과 같이 멤버변수와 함수 원형을 선언한다. | ||
| Line 182: | Line 182: | ||
UINT nPort; | UINT nPort; | ||
m_pClient->GetSockName(strText, nPort); | m_pClient->GetSockName(strText, nPort); | ||
strText = " | strText = "[" + strText + "]" + strData; | ||
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ||
} | } | ||
| Line 188: | Line 188: | ||
void CClientApp::ReceiveData() | void CClientApp::ReceiveData() | ||
{ | { | ||
char temp | char temp[100]; | ||
m_pClient->Receive(temp, sizeof(temp)); | m_pClient->Receive(temp, sizeof(temp)); | ||
| Line 194: | Line 194: | ||
UINT nPort; | UINT nPort; | ||
m_pClient->GetPeerName(strText, nPort); | m_pClient->GetPeerName(strText, nPort); | ||
strText = " | strText = "[" + strText + "]" + temp; | ||
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText); | ||
} | } | ||
| Line 209: | Line 209: | ||
m_pMainWnd->GetDlgItem(IDC_SEND)->EnableWindow(FALSE); | m_pMainWnd->GetDlgItem(IDC_SEND)->EnableWindow(FALSE); | ||
} | } | ||
리소스뷰에서 다이얼로그 항목의 "IDD_CLIENT_DIALOG"을 더블클릭한 후 다음과 같이 편집한다. | |||
리스트 ID : IDC_LIST1 | 리스트 ID : IDC_LIST1 | ||
에디트 박스ID : IDC_DATA | 에디트 박스ID : IDC_DATA | ||
버튼 ID : IDC_SEND, IDC_CONNECT | 버튼 ID : IDC_SEND, IDC_CONNECT | ||
클래스위저드의 CClientDlg에 IDC_CONNECT을 맵핑한 후 다음 코드를 삽입한다. | |||
((CClientApp*)AfxGetApp())->Connect(); | ((CClientApp*)AfxGetApp())->Connect(); | ||
클래스위저드의 CClientDlg에 IDC_SEND를 맵핑한 후 다음 코드를 삽입한다. | |||
CString strData; | CString strData; | ||
GetDlgItemText(IDC_DATA, strData); | GetDlgItemText(IDC_DATA, strData); | ||
| Line 230: | Line 230: | ||
---- | ---- | ||
[[5인용C++스터디]] | [[5인용C++스터디]] | ||
Latest revision as of 23:55, 26 March 2026
1:1 채팅 프로그램을 만들 수 있을 정도로 발표 준비를 할 것.
소켓 이해하기
소켓은 멀리 떨어진 두개의 호스트(서버와 클라이언트)를 연결하는 매개체이다.
전화기에 비유!!!전화기≒소켓
| 전화기 | 소켓 |
| 전화를 받기 위한 '전화 번호' | IP주소 |
| 전화선이 연결되어 전화를 받을 수 있는 상태 | 대기상태(Listen) |
| 전화가 걸려옴 | 연결 요청(Connect) |
| 전화를 받음 | 연결 허락(Accept) |
서버-클라이언트 환경을 만들기 위한 과정을 서버측에서 보자면 다음의 과정을 거치게 된다.
Socket 생성 -> Socket 에 이름연결 (bind)
-> 클라이언트의 연결을 기다림(listen)
-> 클라이언트를 받아들임 (Accept)
-> 클라이언트의 명령을 받아서 적절한 서비스를 수행
클라이언트측에서 서버에 접근하기 위해서는 단순히 소켓을 생성후 서버에 연결(connect) 하기만 하면 된다.
Socket 생성 -> 서버에 연결 시도(connect) -> 서버에 각종 명령을 전달
예제(서버)
Dialog based -> Windows Sockets를 설정
기초 클래스가 CAsyncSocket인 새로운 클래스 CListenSock, CChildSock을 새로 생성한다.
새로 추가된 두개의 클래스를 다음과 같이 편집한다.
클래스위저드의 CListenSock에 가상 함수 OnAccept()를 추가한 후 다음 라인을 삽입한다. ((CServerApp*)AfxGetApp())->Accept();
클래스위저드의 CChildSock에 가상 함수 OnReceive()와 OnClose()를 추가한 후 다음 코드를 삽입한다.
((CServerApp*)AfxGetApp())->CloseChild();
((CServerApp*)AfxGetApp())->ReceiveData();
어플리케이션 클래스에 다음의 멤버변수와 함수 원형을 선언한다.
#include "ChildSock.h"
#include "ListenSock.h"
void InitServer();
void Accept();
void SendData(CString& strData);
void ReceiveData();
void CloseChild();
void CleanUp();
CListenSock* m_pServer;
CChildSock* m_pChild;
어플리케이션 클래스의 생성자에서 추가한 멤버변수를 초기화한다.
m_pServer = NULL;
m_pChild = NULL;
그리고 나서 추가한 멤버함수를 다음과 같이 정의한다.
void CServerApp::InitServer()
{
m_pServer = new CListenSock;
m_pServer->Create(7000);
m_pServer->Listen();
}
void CServerApp::Accept()
{
AfxMessageBox("접속 허용");
m_pChild = new CChildSock;
m_pServer->Accept(*m_pChild);
m_pMainWnd->GetDlgItem(IDC_SEND)->EnableWindow(TRUE);
}
다음으로 데이터 송수신 작업을 하는 함수를 추가한다. 그 다음, 데이터 송수신 후 마무리 작업을 한다.
void CServerApp::SendData(CString& strData)
{
m_pChild->Send(LPCSTR(strData), strData.GetLength()+1);
CString strText;
UINT nPort;
m_pChild->GetSockName(strText, nPort);
strText = "[" + strText + "]" + strData;
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText);
}
void CServerApp::ReceiveData()
{
char temp[1000];
m_pChild->Receive(temp, sizeof(temp));
CString strText;
UINT nPort;
m_pChild->GetPeerName(strText, nPort);
strText = "[" + strText + "]" + temp;
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText);
}
void CServerApp::CleanUp()
{
if (m_pChild)
delete m_pChild;
if (m_pServer)
delete m_pServer;
}
void CServerApp::CloseChild()
{
AfxMessageBox("종료");
delete m_pChild;
m_pMainWnd->GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
}
리소스뷰에서 다이얼로그 항목의 "IDD_SERVER_DIALOG"을 편집한다.
리스트박스ID : IDC_LIST1
에디트 컨트롤ID : IDC_DATA
버튼 컨트롤ID : IDC_SEND
다이얼로그가 초기화될 때 서버로 작동하도록 CServerDlg 클래스의 OnInit Dialog()함수에 다음 코드를 삽입한다.
((CServerApp*)AfxGetApp)->InitServer();
GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
그리고 나서 클래스위저드의 CServerDlg에 IDC_SEND를 맵핑한 후 다음 코드를 추가한다.
CString strData;
GetDlgItemText(IDC_DATA, strData);
((CServerApp*)AfxGetApp())->SendData(strData);
SetDlgItemText(IDC_DATA,"");
예제(클라이언트)
서버와 동일한 방법으로 클라이언트 프로그램에서 사용할 소켓 클래스 CClientSock을 생성(기초 클래스: CAsyncSocket)한다. 그리고 나서 클래스위저드의 CClientSock에 가상함수 OnReceive()와 OnClose()를 추가한 후, 다음 코드를 삽입한다. ((CClientApp*)AfxGetApp())->CloseChild(); ((CClientApp*)AfxGetApp())->ReceiveData(); 서버 접속시 필요한 IP 주소를 입력받기 위해 리소스뷰에서 다이얼로그를 하나 추가한 후 다음과 같이 편집한다. IP주소 컨트롤ID : IDC_IPADDRESS1 버튼 ID : IDOK, IDCANCLE 클래스위저드를 실행하여 CConnectDlg 클래스를 새로 생성한 후 CConnectDlg 클래스에 다음 변수를 추가한다. CString m_strAddress; 그리고 클래스위저드의 CConnectDlg에 IDOK를 맵핑하여 사용자가 입력한 IP 주소를 멤버변수 m_strAddress에 저장한다. GetDlgItemText(IDC_IPADDRESS1, m_strAddress); 어플리케이션 클래스에 다음과 같이 멤버변수와 함수 원형을 선언한다. #include "ClientSock.h" void Connect(); void SendData(CString& strData); void ReceiveData(); void CloseChild(); void CleanUp(); CClientSock* m_pClient;
어플리케이션 클래스의 생성자에서 추가한 멤버변수를 초기화한다.
m_pClient = NULL;
그리고 나서 추가한 멤버함수를 다음과 같이 정의한다.
#include "ConnectDlg.h"
void CClientApp::Connect()
{
CConnectDlg dlg;
if (dlg.DoModal() == IDOK)
{
m_pClient = new CClientSock;
m_pClient->Create();
m_pClient->Connect(dlg.m_strAddress, 7000);
m_pMainWnd->GetDlgItem(IDC_SEND)->EnableWindow(TRUE);
m_pMainWnd->GetDlgItem(IDC_CONNECT)->EnableWindow(FALSE);
}
}
이때 중요한 것은 서버 프로그램의 포트 번호(7000)와 설정할 포트 번호가 일치해야 한다.
이외의 데이터 송수신 과정과 마무리 작업은 서버 프로그램과 유사하다.
void CClientApp::SendData(CString& strData)
{
m_pClient->Send(LPCSTR(strData), strData.GetLength()+1);
CString strText;
UINT nPort;
m_pClient->GetSockName(strText, nPort);
strText = "[" + strText + "]" + strData;
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText);
}
void CClientApp::ReceiveData()
{
char temp[100];
m_pClient->Receive(temp, sizeof(temp));
CString strText;
UINT nPort;
m_pClient->GetPeerName(strText, nPort);
strText = "[" + strText + "]" + temp;
((CListBox*)m_pMainWnd->GetDlgItem(IDC_LIST1))->InsertString(-1, strText);
}
void CClientApp::CleanUp()
{
if (m_pClient)
delete m_pClient;
}
void CClientApp::CloseChild()
{
AfxMessageBox("종료");
m_pMainWnd->GetDlgItem(IDC_SEND)->EnableWindow(FALSE);
}
리소스뷰에서 다이얼로그 항목의 "IDD_CLIENT_DIALOG"을 더블클릭한 후 다음과 같이 편집한다.
리스트 ID : IDC_LIST1
에디트 박스ID : IDC_DATA
버튼 ID : IDC_SEND, IDC_CONNECT
클래스위저드의 CClientDlg에 IDC_CONNECT을 맵핑한 후 다음 코드를 삽입한다.
((CClientApp*)AfxGetApp())->Connect();
클래스위저드의 CClientDlg에 IDC_SEND를 맵핑한 후 다음 코드를 삽입한다.
CString strData;
GetDlgItemText(IDC_DATA, strData);
((CClientApp*)AfxGetApp())->SendData(strData);
SetDlgItemText(IDC_DATA,"");
참고
http://www.rein.pe.kr/technote/read.cgi?board=programing&y_number=260&nnew=2 http://www.rein.pe.kr/technote/read.cgi?board=programing&y_number=261&nnew=2 http://www.rein.pe.kr/technote/read.cgi?board=programing&y_number=262&nnew=2 http://www.rein.pe.kr/technote/read.cgi?board=programing&y_number=263&nnew=2 http://165.194.17.15/pub/upload/p2pChattingProgram