Thinking Different




 

CClientSocket 클래스 구성을 알아보겠습니다. 

 

서버측에서 사용되는 CChatServer 클래스와 핑퐁 구조로 작동되며 서버와 클라이언트 연결의 메인이 되는 소켓 통신 클래스입니다.

 

CChatServer 클래스와 같이 Flatbuffers 를 사용하여 vector schema를 통해 직렬화하여 전송합니다.

 

MFC에서 제공하는 기본 CSocket 클래스를 상속받아 제작하였습니다.

 

 

 

ChatClient.h

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#pragma once
#include <afxsock.h>
 
class CClientSocket : public CSocket
{
public:
    CClientSocket();
    ~CClientSocket();
 
public:
    virtual void OnClose(int nErrorCode);
    virtual void OnReceive(int nErrorCode);
 
public:
    void WritePacket(const CMessage& msg);
    void ProcessPacket(const uint8_t* pData, size_t size);
 
private:
    CMessage m_ReadMessage;
    std::deque<CMessage> m_WriteMessage;
};
 
cs

 

 

 

ChatClient.cpp

 

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#include "pch.h"
#include "ChatClient.h"
 
#include "MFCChatClientDlg.h"
 
 
CClientSocket::CClientSocket()
{
}
 
CClientSocket::~CClientSocket()
{
}
 
 
void CClientSocket::OnClose(int nErrorCode)
{
    ShutDown();
    Close();
 
    CSocket::OnClose(nErrorCode);
 
    AfxMessageBox(_T("There is no connection to the server."));
}
 
void CClientSocket::OnReceive(int nErrorCode)
{
    if (Receive(m_ReadMessage.data(), CMessage::header_length) > 0)
    {
        if (m_ReadMessage.decode_header())
        {
            if (Receive(m_ReadMessage.body(), m_ReadMessage.body_length()) > 0)
            {
                ProcessPacket(m_ReadMessage.body(), m_ReadMessage.body_length());
            }
        }
    }
 
    CSocket::OnReceive(nErrorCode);
}
 
void CClientSocket::WritePacket(const CMessage& msg)
{
    m_WriteMessage.push_back(msg);
 
    if (!m_WriteMessage.empty())
    {
        do
        {
            Send(m_WriteMessage.front().data(), m_WriteMessage.front().length());
 
            m_WriteMessage.pop_front();
        }
        while (!m_WriteMessage.empty());
    }
}
 
 
void CClientSocket::ProcessPacket(const uint8_t* pData, size_t size)
{
    CMFCChatClientDlg* pMainDlg = (CMFCChatClientDlg*)AfxGetMainWnd();
    auto verifier = flatbuffers::Verifier(pData, size);
 
    if (fbs::VerifyRootBuffer(verifier))
    {
        auto root = fbs::GetRoot(pData);
 
        switch (root->packet_type())
        {
        case fbs::Packet_S2C_CONNECT_RES:    // 연결 응답
        {
            auto raw = static_cast<const fbs::S2C_CONNECT_RES*>(root->packet());
 
            if (raw->b_success() == true)
            {
                pMainDlg->AddChat(_T("서버에 접속하였습니다"));
 
                flatbuffers::FlatBufferBuilder builder;
 
                auto data = fbs::CreateC2S_USERLIST_REQ(builder);
                auto packet = fbs::CreateRoot(builder, fbs::Packet_C2S_USERLIST_REQ, data.Union());
 
                builder.Finish(packet);
 
                WritePacket(CMessage(builder.GetBufferPointer(), builder.GetSize()));
            }
            else
            {
                pMainDlg->AddChat(_T("서버 접속 실패!"));
            }
 
            break;
        }
 
        case fbs::Packet_S2C_ENTER_RES:        // 입장 응답
        {
            auto raw = static_cast<const fbs::S2C_ENTER_RES*>(root->packet());
            
            CString str;
            str = raw->name()->c_str();
            str += _T(" 님이 접속하였습니다.");
            
            pMainDlg->AddChat(str);
            pMainDlg->AddUser(CString(raw->name()->c_str()).GetString());
 
            break;
        }
 
        case fbs::Packet_S2C_LEAVE_RES:        // 퇴장 응답
        {
            auto raw = static_cast<const fbs::S2C_LEAVE_RES*>(root->packet());
 
            CString str;
            str = raw->name()->c_str();
            str += _T(" 님이 퇴장하였습니다.");
 
            pMainDlg->AddChat(str);
            pMainDlg->DelUser(CString(raw->name()->c_str()).GetString());
 
            break;
        }
 
        case fbs::Packet_S2C_USERLIST_RES:    // 유저 리스트 응답
        {
            auto raw = static_cast<const fbs::S2C_USERLIST_RES*>(root->packet());
            
            for (auto it = raw->name()->begin(); it != raw->name()->end(); it++)
            {
                pMainDlg->AddUser((*it)->c_str());
            }
 
            break;
        }
 
        case fbs::Packet_S2C_CHAT_RES:        // 채팅 응답
        {
            auto raw = static_cast<const fbs::S2C_CHAT_RES*>(root->packet());
 
            CString str;
            str.Format(_T("%s: %s"), raw->name()->c_str(), raw->message()->c_str());
            
            pMainDlg->AddChat(str);
 
            break;
        }
        }
    }
    else
    {
        AfxMessageBox(_T("Ill-formed message"));
    }
}
 
cs