UbiAnyCard Ver2 2.0
KICC ED785 단말기 연동 TCP 서버
로딩중...
검색중...
일치하는것 없음
TcpServer 클래스 참조final

#include <TcpServer.h>

TcpServer에 대한 협력 다이어그램:
Collaboration graph

클래스

class  Session

Public 타입

using CommandHandler = std::function<std::string(const std::string &, const std::weak_ptr<Session> &)>

Public 멤버 함수

void setHandler (CommandHandler handler)
bool start (uint16_t port)
void stop ()
 TcpServer ()
 ~TcpServer ()

정적 Public 멤버 함수

static std::weak_ptr< SessioncurrentSession ()

Private 멤버 함수

void acceptLoop ()
void closeSocket (SOCKET s)
bool recvAck (SOCKET s, uint32_t timeoutMs)
bool sendAck (SOCKET s)

Private 속성

std::thread m_acceptThread
CommandHandler m_handler
SOCKET m_listen {INVALID_SOCKET}
std::atomic< bool > m_running {false}

멤버 타입정의 문서화

◆ CommandHandler

using TcpServer::CommandHandler = std::function<std::string(const std::string &, const std::weak_ptr<Session> &)>

생성자 & 소멸자 문서화

◆ TcpServer()

TcpServer::TcpServer ( )
58{}

◆ ~TcpServer()

TcpServer::~TcpServer ( )
59{ stop(); }
void stop()
Definition TcpServer.cpp:101

다음을 참조함 : stop().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:

멤버 함수 문서화

◆ acceptLoop()

void TcpServer::acceptLoop ( )
private
124{
125 while (m_running.load())
126 {
127 sockaddr_in caddr{};
128 int clen = sizeof(caddr);
129 SOCKET client = ::accept(m_listen, (sockaddr *)&caddr, &clen);
130
131 if (client == INVALID_SOCKET)
132 {
133 if (!m_running.load())
134 break;
135 std::this_thread::sleep_for(std::chrono::milliseconds(50));
136 continue;
137 }
138
139 Logger::debug(L"클라이언트 연결 수락");
140
141 // 거래당 연결: 요청 수신 → ACK → 처리 → 응답 → ACK 대기 → 연결 종료
142 // 단, PING 명령은 연결 유지 (Keep-Alive)
143 std::thread([this, client]()
144 {
145 auto session = std::make_shared<Session>(client);
146 g_threadSession = session;
147 char buf[4096];
148 bool keepAlive = false;
149
150 // PING의 경우 연결을 유지하고 계속 명령 수신
151 do {
152 std::string request;
153
154 // 1. 요청 수신 (개행으로 종료 판단, 세미콜론은 데이터 구분자)
155 bool reqComplete = false;
156 while (!reqComplete)
157 {
158 int r = ::recv(client, buf, sizeof(buf), 0);
159 if (r <= 0)
160 {
161 session->markClosed();
162 g_threadSession.reset();
163 return;
164 }
165
166 request.append(buf, r);
167
168 // 요청 완료 판단: \n로 끝나면 완료
169 if (!request.empty() && request.back() == '\n')
170 reqComplete = true;
171
172 // 타임아웃 방지: 일정 크기 이상이면 강제 완료
173 if (request.size() > 2048)
174 reqComplete = true;
175 }
176
177 // 요청 정리 (개행/공백 제거)
178 while (!request.empty() && (request.back() == '\r' || request.back() == '\n' || request.back() == ' '))
179 request.pop_back();
180
181 if (request.empty())
182 {
183 Logger::warn(L"빈 요청 수신");
184 session->markClosed();
185 g_threadSession.reset();
186 return;
187 }
188
189 Logger::debug(std::wstring(L"요청 수신: ") + std::wstring(request.begin(), request.end()));
190
191 // PING 명령 확인 (대소문자 무시)
192 std::string cmdCheck = request;
193 std::transform(cmdCheck.begin(), cmdCheck.end(), cmdCheck.begin(),
194 [](unsigned char c) { return (char)std::toupper(c); });
195 keepAlive = (cmdCheck == "PING" || cmdCheck.substr(0, 5) == "PING ");
196
197 // 2. ACK 전송
198 if (!sendAck(client))
199 {
200 Logger::warn(L"ACK 전송 실패");
201 session->markClosed();
202 g_threadSession.reset();
203 return;
204 }
205 Logger::debug(L"ACK 전송 완료");
206
207 // 3. 핸들러 호출 (동기 처리)
208 std::string response;
209 if (m_handler)
210 {
211 response = m_handler(request, session);
212 }
213 else
214 {
215 response = "ERR=NO_HANDLER";
216 }
217
218 if (response.empty())
219 response = "ERR=EMPTY_RESPONSE";
220
221 // 로그 출력 (UTF-8 → UTF-16 변환, 길이 제한)
222 int wlen = ::MultiByteToWideChar(CP_UTF8, 0, response.c_str(), (int)response.size(), nullptr, 0);
223 std::wstring wResp;
224 if (wlen > 0)
225 {
226 wResp.resize(wlen);
227 ::MultiByteToWideChar(CP_UTF8, 0, response.c_str(), (int)response.size(), wResp.data(), wlen);
228 }
229 if (wResp.size() > 300)
230 wResp = wResp.substr(0, 300) + L"...";
231 Logger::debug(L"응답 준비 완료: " + wResp);
232
233 // 4. 응답 전송
234 if (!session->sendLine(response))
235 {
236 Logger::warn(L"응답 전송 중 오류");
237 session->markClosed();
238 g_threadSession.reset();
239 return;
240 }
241
242 int totalSent = static_cast<int>(response.size());
243
244 {
245 std::wstringstream ss;
246 ss << L"응답 전송 완료: " << totalSent << L" bytes";
247 Logger::debug(ss.str());
248 }
249
250 // 5. ACK 대기 (선택적)
251 bool ackOk = recvAck(client, 1000);
252 Logger::debug(ackOk ? L"클라이언트 ACK 수신" : L"클라이언트 ACK 미수신 (무시)");
253
254 if (keepAlive)
255 {
256 Logger::debug(L"PING 명령 - 연결 유지");
257 }
258
259 } while (keepAlive); // PING의 경우 계속 루프
260
261 // 6. 연결 종료
262 session->markClosed();
263 g_threadSession.reset();
264 Logger::debug(L"거래 완료, 연결 종료"); })
265 .detach();
266 }
267}
static thread_local std::weak_ptr< TcpServer::Session > g_threadSession
Definition TcpServer.cpp:6
std::atomic< bool > m_running
Definition TcpServer.h:31
bool recvAck(SOCKET s, uint32_t timeoutMs)
Definition TcpServer.cpp:275
SOCKET m_listen
Definition TcpServer.h:32
bool sendAck(SOCKET s)
Definition TcpServer.cpp:269
CommandHandler m_handler
Definition TcpServer.h:34

다음을 참조함 : g_threadSession, m_handler, m_listen, m_running, recvAck(), sendAck().

다음에 의해서 참조됨 : start().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ closeSocket()

void TcpServer::closeSocket ( SOCKET s)
private
291{
292 if (s != INVALID_SOCKET)
293 {
294 ::shutdown(s, SD_BOTH);
295 ::closesocket(s);
296 }
297}

다음에 의해서 참조됨 : start(), stop().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ currentSession()

std::weak_ptr< TcpServer::Session > TcpServer::currentSession ( )
static
119{
120 return g_threadSession;
121}

다음을 참조함 : g_threadSession.

◆ recvAck()

bool TcpServer::recvAck ( SOCKET s,
uint32_t timeoutMs )
private
276{
277 // Windows 소켓: SO_RCVTIMEO는 DWORD(밀리초) 사용
278 DWORD timeout = static_cast<DWORD>(timeoutMs);
279 ::setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (const char *)&timeout, sizeof(timeout));
280
281 char ackBuf[3] = {0};
282 int r = ::recv(s, ackBuf, 3, 0);
283
284 if (r == 3 && memcmp(ackBuf, ACK_PACKET, 3) == 0)
285 return true;
286
287 return false; // ACK 미수신도 허용
288}
static const char ACK_PACKET[3]
Definition TcpServer.cpp:5

다음을 참조함 : ACK_PACKET.

다음에 의해서 참조됨 : acceptLoop().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ sendAck()

bool TcpServer::sendAck ( SOCKET s)
private
270{
271 int n = ::send(s, ACK_PACKET, sizeof(ACK_PACKET), 0);
272 return n == sizeof(ACK_PACKET);
273}

다음을 참조함 : ACK_PACKET.

다음에 의해서 참조됨 : acceptLoop().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ setHandler()

void TcpServer::setHandler ( CommandHandler handler)
114{
115 m_handler = std::move(handler);
116}

다음을 참조함 : m_handler.

다음에 의해서 참조됨 : wWinMain().

이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ start()

bool TcpServer::start ( uint16_t port)
62{
63 if (m_running.load())
64 return true;
65
66 m_listen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
67 if (m_listen == INVALID_SOCKET)
68 {
69 Logger::error(L"TcpServer: socket 생성 실패");
70 return false;
71 }
72
73 BOOL reuse = TRUE;
74 ::setsockopt(m_listen, SOL_SOCKET, SO_REUSEADDR, (const char *)&reuse, sizeof(reuse));
75
76 sockaddr_in addr{};
77 addr.sin_family = AF_INET;
78 addr.sin_addr.s_addr = ::htonl(INADDR_ANY);
79 addr.sin_port = ::htons(port);
80
81 if (::bind(m_listen, (sockaddr *)&addr, sizeof(addr)) == SOCKET_ERROR)
82 {
83 Logger::error(L"TcpServer: bind 실패");
85 return false;
86 }
87
88 if (::listen(m_listen, SOMAXCONN) == SOCKET_ERROR)
89 {
90 Logger::error(L"TcpServer: listen 실패");
92 return false;
93 }
94
95 m_running = true;
96 m_acceptThread = std::thread(&TcpServer::acceptLoop, this);
97 Logger::info(L"TcpServer: 시작됨 (거래당 연결 모델)");
98 return true;
99}
std::thread m_acceptThread
Definition TcpServer.h:33
void closeSocket(SOCKET s)
Definition TcpServer.cpp:290
void acceptLoop()
Definition TcpServer.cpp:123

다음을 참조함 : acceptLoop(), closeSocket(), m_acceptThread, m_listen, m_running.

다음에 의해서 참조됨 : wWinMain().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

◆ stop()

void TcpServer::stop ( )
102{
103 if (!m_running.exchange(false))
104 return;
105
107 if (m_acceptThread.joinable())
108 m_acceptThread.join();
109
110 Logger::info(L"TcpServer: 정지됨");
111}

다음을 참조함 : closeSocket(), m_acceptThread, m_listen, m_running.

다음에 의해서 참조됨 : wWinMain(), ~TcpServer().

이 함수 내부에서 호출하는 함수들에 대한 그래프입니다.:
이 함수를 호출하는 함수들에 대한 그래프입니다.:

멤버 데이터 문서화

◆ m_acceptThread

std::thread TcpServer::m_acceptThread
private

다음에 의해서 참조됨 : start(), stop().

◆ m_handler

CommandHandler TcpServer::m_handler
private

다음에 의해서 참조됨 : acceptLoop(), setHandler().

◆ m_listen

SOCKET TcpServer::m_listen {INVALID_SOCKET}
private
32{INVALID_SOCKET};

다음에 의해서 참조됨 : acceptLoop(), start(), stop().

◆ m_running

std::atomic<bool> TcpServer::m_running {false}
private
31{false};

다음에 의해서 참조됨 : acceptLoop(), start(), stop().


이 클래스에 대한 문서화 페이지는 다음의 파일들로부터 생성되었습니다.: