티스토리 뷰

기존 프로젝트에 소켓 추가하기

MFC에서 소켓을 지정했을경우

 첫번째
APP의 InitInstance에서 소켓 라이브러리 초기화
BOOL CMyApp::InitInstance() // 다이얼로그 방식이면 ~Dlg::OnInitDialog() 에서 추가
{
     if (!AfxSocketInit())
     {
          AfxMessageBox("Windows 소켓 초기화에 실패하였습니다.");
          return FALSE;
     }
   ....
}

두번째
stdafx.h에 소켓헤더 추가
#include <afxsock.h>  // MFC socket extensions

아래 윈속 프로그래밍 순서대로 하면 된다.

=================================================
윈속 프로그래밍

A. 서버 구현

프로젝트 만들때 옵션에서 Windows 소켓 을 선택해주고 아래처럼 MFC 클래스 2개 추가한다.

1. CListenSocket 추가 및 함수와 변수 추가
class CListenSocket : public CAsyncSocket
{
......

public:
    CPtrList m_ptrClientSocketList; // 연결된 Client Socket List 저장하는 변수
    virtual void OnAccept(int nErrorCode); // Client에서 연결 시도 치 자동 호출되는 함수

}

2. CClientSocket 추가 및 함수와 변수 추가
class CClientSocket : public CSocket
{
........
public:
    void SetListenSocket(CAsyncSocket* pSocket); 
    CAsyncSocket* m_pListenSocket; // 소켓 리스트에 접근하기 위해서 Listen 소켓의 주소를 저장 해둔다.

}

3. 가상함수 OnAccept() 추가 및 코드 추가
#include "ClientSocket.h"
void CListenSocket::OnAccept(int nErrorCode) // 새로운 클라이언트의 연결을 받을때 자동 호출됨.
{
    // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
    CClientSocket* pClient = new CClientSocket;
    if(Accept(*pClient))
    {
        pClient->SetListenSocket(this);
        m_ptrClientSocketList.AddTail(pClient);
    }
    else
    {
        delete pClient;
        AfxMessageBox("Accept 실패.");
    }

    CAsyncSocket::OnAccept(nErrorCode);
}

4. CloseClientSocket() 추가 및 코드 추가
void CListenSocket::CloseClientSocket(CClientSocket* pClient) // 프로그램 종료 전에 연결된 모든 클라이언트 소켓을 모두 닫고 할당된 메모리를 해제하고 네트워크 연결을 모두 종료한다.
{
    POSITION pos;
    pos = m_ptrClientSocketList.Find(pClient);
    if(pos != NULL)
    {
        if(pClient != NULL)
        {
            pClient->ShutDown();
            pClient->Close();
        }
        m_ptrClientSocketList.RemoveAt(pos);
        delete pClient;
    }
}

5. SendOrderResultDataAll() 추가 및 코드 추가
void CListenSocket::SendOrderResultDataAll(char* pszBuffer) // 한 클라이언트에서 받은 메시지를 연결된 모든 클라이언트에게 전송한다.
{
     POSITION pos;
     pos = m_ptrClientSocketList.GetHeadPosition();
     CClientSocket* pClient = NULL;
     while(pos != NULL)
     {
          pClient = (CClientSocket*)m_ptrClientSocketList.GetNext(pos);
          if(pClient != NULL)
              pClient->Send(pszBuffer, lstrlen(pszBuffer));
     }
}

6. SetListenSocket() 코드 추가
#include "ListenSocket.h"
void CClientSocket::SetListenSocket(CAsyncSocket* pSocket)
{
     m_pListenSocket = pSocket; // 소켓 리스트에 접근하기 위해서 Listen 소켓의 주소를 저장해둔다.
}

7. CClientSocket 클래스에 가상함수 OnClose() 추가 및 코드 추가
void CClientSocket::OnClose(int nErrorCode)
{
     // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.

     CSocket::OnClose(nErrorCode);
     CListenSocket* pServerSocket = (CListenSocket*)m_pListenSocket;
     pServerSocket->CloseClientSocket(this);
}

8. CClientSocket 클래스에 가상함수 OnReceive() 추가 및 코드 추가
#define BUFFER_SIZE 512 // 코드추가
// 클라이언트로부터 메시를 받으면 자동 호출된다.
void CClientSocket::OnReceive(int nErrorCode)
{
 // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
     CString tmp = "", strIPAddress = "";
     UINT uPortNumber = 0;
     char szBuffer[BUFFER_SIZE];
     ::ZeroMemory(szBuffer, BUFFER_SIZE);
     GetPeerName(strIPAddress, uPortNumber);
     if(Receive(szBuffer, BUFFER_SIZE) > 0)
    {
          //CServerDemoDlg* pMain = (CServerDemoDlg*)AfxGetMainWnd(); // 해당 다이얼로그 설정
          tmp.Format("[%s:%d] : %s", strIPAddress, uPortNumber, szBuffer);
          //pMain->m_List.AddString(tmp); // 리스트컨트롤에 출력
          AfxMessageBox(tmp);

          CListenSocket* pServerSocket = (CListenSocket*)m_pListenSocket;
          pServerSocket->SendOrderResultDataAll(szBuffer); // 한 클라이언트로 부터 받은 메시지를 모든 클라이언트에게 전송한다.
     }

 CSocket::OnReceive(nErrorCode);
}

9. 프로젝트가 다이얼로그 방식이라면 Dialog 클래스에, 아니면 ~App 클래스에 변수 추가
#include "ListenSocket.h"

public:
    CListenSocket* m_pListenSocket;

10. 다이얼로그 방식이라면 Dialog 클래스의 OnInitDialog()에, 아니면 ~App 클래스의 InitInstance() 에 코드 추가

// 소켓 생성, 소켓에 바인드되는 포트번호와 TCP 를 의미하는 SOCK_STREAM 인수를 사용
 m_pListenSocket = new CListenSocket;
 if(m_pListenSocket->Create(21000, SOCK_STREAM)) // 포트번호, TCP
 {
      if(!m_pListenSocket->Listen()) // 포트 충돌인지 검사
      {
           CString tmp;
           tmp.Format("Listen 실패!!!\r\n다른 프로그램에서 [포트번호 : 21000] 를 사용 중인지 확인해주세요.");
      }
 }
 else
     AfxMessageBox("소켓 생성 실패");

11. 프로젝트가 Dialog 방식이라면 WM_DESTROY 메시지 핸들러 추가 및 코드 추가
아니면 ~App클래스의 ExitInstance() 에 코드 추가

// 연결된 모든 클라이언트와의 연결을 종료하고 객체를 삭제한 다음 서버 소켓도 삭제한다.
if(m_pListenSocket != NULL)
 {
      POSITION pos;
      pos = m_pListenSocket->m_ptrClientSocketList.GetHeadPosition();
      CClientSocket* pClient = NULL;
      // 프로그램 종료 전에 메모리 해제

      while(pos != NULL)
      {
           pClient = (CClientSocket*)m_pListenSocket->m_ptrClientSocketList.GetNext(pos);
           if(pClient != NULL)
           {
                pClient->ShutDown();
                pClient->Close();
                delete pClient;
           }
      }
      m_pListenSocket->ShutDown();
      m_pListenSocket->Close();
      delete m_pListenSocket;
 }

B. 클라이언트 프로그로그래밍

1. Dialog 방식으로 프로그램을 만든다.
2. CSocket 클래스를 public 으로 상속받는 CConnectSocket 클래스 추가 
class CConnectSocket : public CSocket
{
public:
 CConnectSocket();
 virtual ~CConnectSocket();
};

3. OnReceive() 가상함수를 오버드라이브하고 코드 추가
// 서버에서 메시지를 받을때 자동 호출되는 함수
void CConnectSocket::OnReceive(int nErrorCode)
{
     // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
     char szBuffer[BUFFER_SIZE];
     ::ZeroMemory(szBuffer, BUFFER_SIZE);
     if(Receive(szBuffer, BUFFER_SIZE))
     {
      CStockOrderClientDlg* pMain = (CStockOrderClientDlg*)AfxGetMainWnd();
      //Main->m_List.AddString(szBuffer);
      CString tmp;
      tmp.Format("%s", szBuffer);
      AfxMessageBox(tmp);
     }

     CSocket::OnReceive(nErrorCode);
}

4. OnClose() 가상함수를 오버드라이브하고 코드 추가
// 서버와 연결이 종료되면 PostQuitMessage()를 호출해서 프로그램을 종료한다.
void CConnectSocket::OnClose(int nErrorCode)
{
     // TODO: 여기에 특수화된 코드를 추가 및/또는 기본 클래스를 호출합니다.
     ShutDown();
     Close();
     CSocket::OnClose(nErrorCode);
     AfxMessageBox("서버와 연결이 종료되었습니다.");
     ::PostQuitMessage(0);
}

5. ~Dlg 클래스의 OnInitDialog() 에 코드 추가
// 소켓 만들고 서버와 연결한다
m_Socket.Create();
 if(m_Socket.Connect("127.0.0.1", 90000) == FALSE) // 서버 연결 실패하면 프로그램 종료한다.
 {
      AfxMessageBox("서버 연결 실패");
      PostQuitMessage(0);
      return FALSE;
 }

6. 전송버튼 누르면 메시를 서버에 전송한다.
void CStockOrderClientDlg::OnBnClickedButtonSend()
{
     // TODO: 여기에 컨트롤 알림 처리기 코드를 추가합니다.
     UpdateData(TRUE);
     m_Socket.Send((const char*)m_csMsg, m_csMsg.GetLength());
     m_csMsg = "";
     UpdateData(FALSE);
}

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/06   »
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