124{
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 {
134 break;
135 std::this_thread::sleep_for(std::chrono::milliseconds(50));
136 continue;
137 }
138
139 Logger::debug(L"클라이언트 연결 수락");
140
141
142
143 std::thread([this, client]()
144 {
145 auto session = std::make_shared<Session>(client);
147 char buf[4096];
148 bool keepAlive = false;
149
150
151 do {
152 std::string request;
153
154
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();
163 return;
164 }
165
166 request.append(buf, r);
167
168
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();
186 return;
187 }
188
189 Logger::debug(std::wstring(L"요청 수신: ") + std::wstring(request.begin(), request.end()));
190
191
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
199 {
200 Logger::warn(L"ACK 전송 실패");
201 session->markClosed();
203 return;
204 }
205 Logger::debug(L"ACK 전송 완료");
206
207
208 std::string response;
210 {
212 }
213 else
214 {
215 response = "ERR=NO_HANDLER";
216 }
217
218 if (response.empty())
219 response = "ERR=EMPTY_RESPONSE";
220
221
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
234 if (!session->sendLine(response))
235 {
236 Logger::warn(L"응답 전송 중 오류");
237 session->markClosed();
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
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);
260
261
262 session->markClosed();
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