/
tytyshka
/
Typing_Race_Game
Обзор
Документация
Войти
/
tytyshka
/
Typing_Race_Game
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
Client
GameClient/net_client.cpp
153 строки
5 KB
tytyshka
Файлы клиента
16 дек 2025, 21:52
16 дек 2025, 21:52
7041c0b
Код
Авторство
О чём код?
#include "net_client.h" #include <iostream> #include <vector> #include <cstring> #include <chrono> NetClient::NetClient() {} NetClient::~NetClient() { disconnect(); } bool NetClient::connect_to(const std::string& host, int port) { if (connected_) return true; WSADATA wsa; if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { std::cerr << "[NetClient] WSAStartup failed\n"; return false; } sock_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock_ == INVALID_SOCKET) { std::cerr << "[NetClient] socket failed: " << WSAGetLastError() << "\n"; WSACleanup(); return false; } sockaddr_in serv{}; serv.sin_family = AF_INET; serv.sin_port = htons((u_short)port); if (inet_pton(AF_INET, host.c_str(), &serv.sin_addr) != 1) { // try resolve by name addrinfo hints{}, * res = nullptr; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; if (getaddrinfo(host.c_str(), nullptr, &hints, &res) == 0 && res) { sockaddr_in* a = (sockaddr_in*)res->ai_addr; serv.sin_addr = a->sin_addr; freeaddrinfo(res); } else { std::cerr << "[NetClient] inet_pton and getaddrinfo failed\n"; closesocket(sock_); WSACleanup(); return false; } } if (::connect(sock_, (sockaddr*)&serv, sizeof(serv)) == SOCKET_ERROR) { std::cerr << "[NetClient] connect failed: " << WSAGetLastError() << "\n"; closesocket(sock_); WSACleanup(); return false; } connected_ = true; reader_thread_ = std::thread(&NetClient::reader_loop, this); std::cout << "[NetClient] connected\n"; return true; } void NetClient::disconnect() { if (!connected_) return; connected_ = false; shutdown(sock_, SD_BOTH); closesocket(sock_); q_cv_.notify_all(); if (reader_thread_.joinable()) reader_thread_.join(); WSACleanup(); std::cout << "[NetClient] disconnected\n"; } bool NetClient::send_json(const json& j) { if (!connected_) return false; std::string body = j.dump(); uint32_t len = (uint32_t)body.size(); uint32_t net = htonl(len); // send header int total = 0; const char* hdr = (const char*)&net; while (total < 4) { int s = ::send(sock_, hdr + total, 4 - total, 0); if (s == SOCKET_ERROR) { std::cerr << "[NetClient] send header failed\n"; return false; } total += s; } // send body total = 0; const char* data = body.data(); int tosend = (int)body.size(); while (total < tosend) { int s = ::send(sock_, data + total, tosend - total, 0); if (s == SOCKET_ERROR) { std::cerr << "[NetClient] send body failed\n"; return false; } total += s; } return true; } json NetClient::receive_next() { std::unique_lock<std::mutex> lk(q_mtx_); q_cv_.wait(lk, [&] { return !incoming_q_.empty() || !connected_; }); if (incoming_q_.empty()) return json::object(); json j = std::move(incoming_q_.front()); incoming_q_.pop(); return j; } bool NetClient::try_receive(json& out) { std::lock_guard<std::mutex> lk(q_mtx_); if (incoming_q_.empty()) return false; out = std::move(incoming_q_.front()); incoming_q_.pop(); return true; } void NetClient::reader_loop() { while (connected_) { // read 4 bytes header uint32_t netlen = 0; int got = 0; char* ph = (char*)&netlen; while (got < 4) { int r = ::recv(sock_, ph + got, 4 - got, 0); if (r == 0 || r == SOCKET_ERROR) { connected_ = false; break; } got += r; } if (!connected_) break; uint32_t len = ntohl(netlen); if (len == 0 || len > 10 * 1024 * 1024) { std::cerr << "[NetClient] invalid len\n"; connected_ = false; break; } std::vector<char> buf(len); int rec = 0; while (rec < (int)len) { int r = ::recv(sock_, buf.data() + rec, (int)(len - rec), 0); if (r == 0 || r == SOCKET_ERROR) { connected_ = false; break; } rec += r; } if (!connected_) break; try { std::string s(buf.begin(), buf.end()); json j = json::parse(s); { std::lock_guard<std::mutex> lk(q_mtx_); incoming_q_.push(std::move(j)); } q_cv_.notify_one(); } catch (std::exception& ex) { std::cerr << "[NetClient] JSON parse error: " << ex.what() << "\n"; } } // notify waiting receivers q_cv_.notify_all(); }