직렬화 함수 작성 끝

This commit is contained in:
2025-06-09 03:47:48 +09:00
parent 5ba62b5312
commit 50c9bd68fc
47 changed files with 324 additions and 201 deletions

View File

@@ -18,83 +18,27 @@ std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
#endif
utils::ThreadPool tp(0);
Network::IOCP iocp;
iocp.init(&tp, SessionProtocol::TLS);
iocp.init(&tp, SessionProtocol::TCP);
Network::Address addr;
in6_addr in6addr;
addr.set(AF_INET, "43.200.173.151", 9010);
addr.set(AF_INET6, "::1", 9010);
Network::Socket sock;
Network::TCPSocket TCPSock;
Network::UDPSocket UDPSock;
TCPSock.init(AF_INET);
UDPSock.init(AF_INET);
TCPSock.init(AF_INET6);
UDPSock.init(AF_INET6);
sock = TCPSock;
if (sock.connect(addr) == INVALID_SOCKET) {
spdlog::error("connect()");
std::exit(EXIT_FAILURE);
}
// SSL_CTX* ctx = ::SSL_CTX_new(::OSSL_QUIC_client_method());
SSL_CTX* ctx = SSL_CTX_new(TLS_client_method());
if (ctx == NULL) {
printf("Failed to create the SSL_CTX\n");
std::exit(EXIT_FAILURE);
}
// SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, NULL);
/* * 인증서 검증을 비활성화합니다.
* SSL_VERIFY_NONE 플래그를 사용하면 클라이언트는 서버 인증서를 요청하거나
* 확인하지 않습니다. 경고: 보안상 매우 위험합니다. 테스트용으로만 사용하세요.
*/
SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
/* Use the default trusted certificate store */
if (!SSL_CTX_set_default_verify_paths(ctx)) {
printf("Failed to set the default trusted certificate store\n");
std::exit(EXIT_FAILURE);
}
Network::IOCPPASSINDATA* data = new Network::IOCPPASSINDATA(16 * 1024, ctx);
Network::IOCPPASSINDATA* data = new Network::IOCPPASSINDATA(16 * 1024);
data->socket = std::make_shared<Network::Socket>(sock);
data->IOCPInstance = &iocp;
char buf[4096];
int ret = 0;
while ((ret = SSL_connect(data->ssl.get())) != 1) {
if (BIO_ctrl_pending(SSL_get_wbio(data->ssl.get())) > 0) {
// wbio에서 암호화된 데이터를 읽어서
int bytes_to_write =
BIO_read(SSL_get_wbio(data->ssl.get()), buf, sizeof(buf));
if (bytes_to_write > 0) {
// 소켓으로 전송
send(sock.sock, buf, bytes_to_write, 0);
}
}
int err = SSL_get_error(data->ssl.get(), ret);
if (err == SSL_ERROR_WANT_READ) {
// OpenSSL이 소켓에서 데이터를 더 읽어오길 원함
// 소켓에서 데이터를 읽어서
int bytes_read = recv(sock.sock, buf, sizeof(buf), 0);
if (bytes_read > 0) {
// rbio에 써준다
BIO_write(SSL_get_rbio(data->ssl.get()), buf, bytes_read);
} else if (bytes_read == 0) {
// 소켓 연결이 끊김
fprintf(stderr, "Socket closed during handshake.\n");
return 0;
} else {
// 소켓 에러 (EAGAIN/EWOULDBLOCK은 논블록킹 소켓에서 정상)
// 실제 프로덕션 코드에서는 이 부분을 정교하게 처리해야 합니다.
}
} else {
printf("Failed to connect to server\n");
std::exit(EXIT_FAILURE);
}
continue;
}
iocp.registerTCPSocket(data);
std::vector<Network::IOCPPASSINDATA*> send_data;
@@ -102,14 +46,14 @@ std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
auto snowflake = utils::GenerateID();
auto timestamp = std::to_string(snowflake.timestamp);
::memcpy(
data->wsabuf.buf, timestamp.c_str(), 128
/*(data->bufsize < timestamp.size()) ? data->bufsize : timestamp.size()*/);
data->wsabuf.len = timestamp.size();
data->wsabuf.buf, timestamp.c_str(),
(data->bufsize < timestamp.size()) ? data->bufsize : timestamp.size());
data->wsabuf.len = 16 * 1024;
send_data.push_back(data);
iocp.send(sock.sock, &send_data);
Network::IOCPPASSINDATA* recv_data =
new Network::IOCPPASSINDATA(16 * 1024, ctx);
new Network::IOCPPASSINDATA(16 * 1024);
recv_data->socket = std::make_shared<Network::Socket>(sock);
recv_data->IOCPInstance = &iocp;
while (!iocp.recv(recv_data)); // 어떤 데이터를 읽는걸 보장받고 싶다면 그냥

View File

@@ -1,30 +0,0 @@
#include "vulkan_engine/asset/object/model.h"
#include "vulkan_engine/vulkan/graphics.h"
namespace veng {
Model::~Model() {
if (graphics_ == nullptr) return;
graphics_->DestroyTexture(material.texture_handle);
graphics_->DestroyBuffer(vertex_buffer);
graphics_->DestroyBuffer(index_buffer);
}
void veng::Model::Update(float dt) {
linear_velocity += linear_acceleration * dt;
position += linear_velocity * dt;
angular_velocity += angular_acceleration * dt;
if (glm::length(angular_velocity) > 1e-6f) {
rotation =
glm::normalize(glm::rotate(rotation, glm::length(angular_velocity * dt),
glm::normalize(angular_velocity)));
}
transform = glm::translate(glm::mat4(1.0f), position) *
glm::mat4_cast(rotation) * glm::scale(glm::mat4(1.0f), scale);
}
} // namespace veng

View File

@@ -4,10 +4,92 @@ set(PROJECT_NAME "Server")
project(${PROJECT_NAME})
add_executable(${PROJECT_NAME}
"${CMAKE_CURRENT_SOURCE_DIR}/src/echoserver.cpp"
find_package(Vulkan REQUIRED)
find_package(OpenSSL REQUIRED)
include(FetchContent)
FetchContent_Declare(
glm
GIT_REPOSITORY "https://github.com/g-truc/glm.git"
GIT_TAG "1.0.1"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(glm)
FetchContent_Declare(
spdlog
GIT_REPOSITORY "https://github.com/gabime/spdlog.git"
GIT_TAG "v1.15.2"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(spdlog)
FetchContent_Declare(
glfw
GIT_REPOSITORY "https://github.com/glfw/glfw.git"
GIT_TAG "3.4"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(glfw)
FetchContent_Declare(
GSL
GIT_REPOSITORY "https://github.com/microsoft/GSL.git"
GIT_TAG "v4.2.0"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(GSL)
FetchContent_Declare(
ASSIMP
GIT_REPOSITORY "https://github.com/assimp/assimp.git"
GIT_TAG "v5.4.3"
GIT_SHALLOW ON
)
FetchContent_MakeAvailable(ASSIMP)
file(GLOB_RECURSE Sources CONFIGURE_DEPENDS
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
)
add_executable(${PROJECT_NAME} ${RootProjectSources} ${Sources})
target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan)
target_link_libraries(${PROJECT_NAME} PRIVATE glm)
target_link_libraries(${PROJECT_NAME} PRIVATE glfw)
target_link_libraries(${PROJECT_NAME} PRIVATE Microsoft.GSL::GSL)
target_link_libraries(${PROJECT_NAME} PRIVATE spdlog)
target_link_libraries(${PROJECT_NAME} PRIVATE assimp::assimp)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::Crypto)
target_link_libraries(${PROJECT_NAME} PRIVATE OpenSSL::SSL)
if(WIN32)
target_link_libraries(${PROJECT_NAME} PRIVATE ws2_32)
endif()
endif()
if(UNIX AND NOT APPLE AND CMAKE_BUILD_TYPE STREQUAL "Release")
set_target_properties(${PROJECT_NAME} PROPERTIES
BUILD_WITH_INSTALL_RPATH TRUE
INSTALL_RPATH "$ORIGIN"
SKIP_BUILD_RPATH FALSE
BUILD_RPATH "$ORIGIN"
)
endif()
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../include" "${CMAKE_CURRENT_SOURCE_DIR}/include")
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
target_precompile_headers(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../include/precomp.h")
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different
"$<TARGET_FILE:spdlog>"
"$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMENT "Copying spdlog DLL/so to output directory"
)
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory
"$<TARGET_FILE_DIR:spdlog>"
"$<TARGET_FILE_DIR:${PROJECT_NAME}>"
COMMENT "Copying spdlog library files and symlinks to output directory"
)

View File

@@ -1,93 +0,0 @@
#pragma once
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ws2bth.h>
#include <ws2def.h>
#include <windows.h>
#define in_addr_t ULONG
#elif __linux__
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <errno.h>
#include <netinet/in.h>
#include <sys/eventfd.h>
#define SOCKET int
#define INVALID_SOCKET -1
#define SOCKET_ERROR -1
#else
#error "이 플랫폼은 지원되지 않습니다."
#endif
#include <chrono>
void err_quit(const char *msg) {
char *msgbuf = strerror(errno);
fprintf(stderr, "[%s] %s\n", msg, msgbuf);
exit(1);
}
void err_display(const char *msg) {
char *msgbuf = strerror(errno);
fprintf(stderr, "[%s] %s\n", msg, msgbuf);
}
#define LISTENIP "::"
#define LISTENPORT 9010
#define BUFSIZE 100
int main(int argc, char *argv[]) {
WSADATA wsa;
if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) {
err_quit("WSAStartup()");
return EXIT_FAILURE;
}
SOCKET listenSocket = socket(AF_INET6, SOCK_STREAM, 0);
if (listenSocket == INVALID_SOCKET) err_quit("socket()");
struct sockaddr_in6 serverAddr;
memset(&serverAddr, 0, sizeof(serverAddr));
serverAddr.sin6_family = AF_INET6;
inet_pton(AF_INET6, LISTENIP, &serverAddr.sin6_addr);
serverAddr.sin6_port = htons(LISTENPORT);
if (SOCKET_ERROR ==
bind(listenSocket, (struct sockaddr *)&serverAddr, sizeof(serverAddr)))
err_quit("bind()");
if (SOCKET_ERROR == listen(listenSocket, SOMAXCONN)) err_quit("listen()");
SOCKET client_sock;
struct sockaddr_in6 client_addr;
socklen_t addr_len;
addr_len = sizeof(client_addr);
printf("Waiting for connection...\n");
client_sock =
accept(listenSocket, (struct sockaddr *)&client_addr, &addr_len);
if (client_sock == INVALID_SOCKET) err_quit("accept()");
printf("Connection established!\n");
char buf[BUFSIZE + 1];
while (2) {
int retVal = recv(client_sock, buf, BUFSIZE, 0);
if (retVal == SOCKET_ERROR)
err_display("recv()");
else if (retVal == 0)
break;
char ipv6str[INET6_ADDRSTRLEN];
inet_ntop(AF_INET6, &client_addr, ipv6str, sizeof(ipv6str));
buf[retVal] = '\0';
printf("[TCP/%s:%d] %s\n", ipv6str, ntohs(client_addr.sin6_port), buf);
if (SOCKET_ERROR == send(client_sock, buf, BUFSIZE, 0))
err_display("send()");
}
WSACleanup();
}

77
Server/src/server.cpp Normal file
View File

@@ -0,0 +1,77 @@
#include <chrono>
#include "socket/iocp.h"
#include "socket/tcp_socket.h"
#include "socket/udp_socket.h"
#include "socket/wsa_manager.h"
#include "utils/log.h"
#include "utils/snowflake.h"
#include "socket/packet.h"
#define LISTENIP "::"
#define LISTENPORT 9010
void EchoClient(utils::ThreadPool* tp, Network::IOCP* iocp,
Network::TCPSocket NewSock, Network::Address NewAddr) {
Network::IOCPPASSINDATA* recv_data = new Network::IOCPPASSINDATA(16 * 1024);
recv_data->socket = std::make_shared<Network::Socket>(NewSock);
recv_data->IOCPInstance = iocp;
auto timestamp = std::chrono::system_clock::now();
while (!iocp->recv(recv_data)) {
if (std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::system_clock::now() - timestamp)
.count() == 1000) {
tp->enqueueJob(EchoClient, iocp, NewSock, NewAddr);
return;
}
}
std::vector<Network::IOCPPASSINDATA*> send_data;
recv_data->event = Network::IOCPEVENT::WRITE;
send_data.push_back(recv_data);
iocp->send(NewSock.sock, &send_data);
tp->enqueueJob(EchoClient, iocp, NewSock, NewAddr);
}
int main(int argc, char* argv[]) {
Network::WSAManager wsamanager;
#if !defined(NDEBUG)
utils::setDefaultLogger(spdlog::level::level_enum::debug, "log.log", 1024, 2);
#endif
utils::ThreadPool tp(0);
Network::IOCP iocp;
iocp.init(&tp, SessionProtocol::TCP);
Network::Address addr;
addr.set(AF_INET6, "::", 9010);
Network::Socket* sock;
Network::TCPSocket TCPSock;
TCPSock.init(AF_INET6);
sock = &TCPSock;
if (TCPSock.bind(addr) == INVALID_SOCKET) {
spdlog::error("bind()");
std::exit(EXIT_FAILURE);
}
if (TCPSock.listen(SOMAXCONN) == INVALID_SOCKET) {
spdlog::error("listen()");
std::exit(EXIT_FAILURE);
}
while (true) {
Network::TCPSocket NewSock;
Network::Address NewAddr;
NewAddr.length = addr.length;
spdlog::info("Waiting for connection");
TCPSock.accept(NewSock, NewAddr);
Network::IOCPPASSINDATA* data = new Network::IOCPPASSINDATA(16 * 1024);
data->socket = std::make_shared<Network::Socket>(NewSock);
data->IOCPInstance = &iocp;
iocp.registerTCPSocket(data);
tp.enqueueJob(EchoClient, &iocp, NewSock, NewAddr);
}
}

View File

@@ -176,9 +176,12 @@ void IOCP::iocpWatcher_(utils::ThreadPool* IOCPThread) {
std::vector<char> buf(16384); // SSL_read최대 반환 크기
int red_data = 0;
std::lock_guard lock(*GetRecvQueueMutex_(sock));
auto queue_list = GetRecvQueue_(data->socket->sock);
auto queue_list = GetRecvQueue_(sock);
if (data->event == IOCPEVENT::READ) {
if (proto_ == SessionProtocol::TLS || proto_ == SessionProtocol::QUIC) {
if (proto_ == SessionProtocol::TLS ||
proto_ == SessionProtocol::QUIC) { // DEPRECATED. openssl을 사용할 수가
// 없기 때문에 추후 완성 뒤에 기능을
// 붙이든 해야 할 듯 함.
// DEBUG: BIO_write 전 OpenSSL 에러 스택 확인 (혹시 모를 이전 에러)
ERR_print_errors_fp(stderr); // 이미 오류 스택에 뭔가 있는지 확인용
fprintf(stderr, "--- Before BIO_write ---\n");

View File

@@ -41,7 +41,7 @@ Socket::operator SOCKET() {
void Socket::set(const SOCKET __sock, int __domain) {
if (__sock == INVALID_SOCKET) {
spdlog::critical("socket()");
spdlog::error("set failed errno:{} {}", errno, strerror(errno));
std::exit(EXIT_FAILURE);
}

View File

@@ -11,9 +11,14 @@ int TCPSocket::listen(int __n) {
}
void TCPSocket::accept(TCPSocket &newSock, Address &__addr) {
newSock.set(::accept(sock, &__addr.addr, &__addr.length), domain);
SOCKET newsock = INVALID_SOCKET;
newsock = ::accept(sock, &__addr.addr, &__addr.length);
if (newsock == INVALID_SOCKET) {
spdlog::error("accept() errno:{} {}", errno, strerror(errno));
std::exit(EXIT_FAILURE);
}
newSock.set(newsock, domain);
memcpy(&newSock.remoteAddr, &__addr, sizeof(Address));
if (newSock.sock == INVALID_SOCKET) spdlog::error("accept()");
}
int TCPSocket::connect(Address &serveraddr) {

View File

@@ -0,0 +1,91 @@
#include "vulkan_engine/asset/object/model.h"
#include "vulkan_engine/vulkan/graphics.h"
namespace veng {
Model::~Model() {
if (graphics_ == nullptr) return;
graphics_->DestroyTexture(material.texture_handle);
graphics_->DestroyBuffer(vertex_buffer);
graphics_->DestroyBuffer(index_buffer);
}
template <typename T>
static void Append(std::vector<char>& dst, const T& data) {
const char* ptr = reinterpret_cast<const char*>(&data);
dst.insert(dst.end(), ptr, ptr + sizeof(T));
}
std::vector<char> Model::Serialize() {
std::vector<char> serialized;
Append(serialized, ID);
Append(serialized, transform);
Append(serialized, position);
Append(serialized, linear_velocity);
Append(serialized, linear_acceleration);
Append(serialized, rotation);
Append(serialized, angular_velocity);
Append(serialized, angular_acceleration);
Append(serialized, scale);
Append(serialized, original_offset);
Append(serialized, radius);
uint8_t vis = visible ? 1 : 0;
uint8_t col = colision ? 1 : 0;
Append(serialized, vis);
Append(serialized, col);
return serialized;
}
template <typename T>
static void Extract(const std::vector<char>& src, size_t& offset, T& out) {
std::memcpy(&out, src.data() + offset, sizeof(T));
offset += sizeof(T);
}
void Model::Deserialize(std::vector<char> data) {
size_t offset = 0;
Extract(data, offset, ID);
Extract(data, offset, transform);
Extract(data, offset, position);
Extract(data, offset, linear_velocity);
Extract(data, offset, linear_acceleration);
Extract(data, offset, rotation);
Extract(data, offset, angular_velocity);
Extract(data, offset, angular_acceleration);
Extract(data, offset, scale);
Extract(data, offset, original_offset);
Extract(data, offset, radius);
uint8_t vis = 0, col = 0;
Extract(data, offset, vis);
Extract(data, offset, col);
visible = vis != 0;
colision = col != 0;
}
void veng::Model::Update(float dt) {
linear_velocity += linear_acceleration * dt;
position += linear_velocity * dt;
angular_velocity += angular_acceleration * dt;
if (glm::length(angular_velocity) > 1e-6f) {
rotation =
glm::normalize(glm::rotate(rotation, glm::length(angular_velocity * dt),
glm::normalize(angular_velocity)));
}
transform = glm::translate(glm::mat4(1.0f), position) *
glm::mat4_cast(rotation) * glm::scale(glm::mat4(1.0f), scale);
}
} // namespace veng

View File

@@ -82,11 +82,12 @@ struct IOCPPASSINDATA {
wsabuf.len = bufsize;
}
IOCPPASSINDATA(const IOCPPASSINDATA& other) {
/*IOCPPASSINDATA(const IOCPPASSINDATA& other) {
if (this != &other) {
std::memset(&overlapped, 0, sizeof(overlapped));
event = other.event;
socket = other.socket;
ssl = other.ssl;
transferredbytes = other.transferredbytes;
bufsize = other.bufsize;
IOCPInstance = other.IOCPInstance;
@@ -97,18 +98,19 @@ struct IOCPPASSINDATA {
wsabuf.len = other.bufsize;
std::memcpy(wsabuf.buf, other.wsabuf.buf, other.wsabuf.len);
}
}
}*/
~IOCPPASSINDATA() {
if (wsabuf.buf != nullptr) delete[] wsabuf.buf;
wsabuf.buf = nullptr;
}
IOCPPASSINDATA& operator=(const IOCPPASSINDATA& other) {
/*IOCPPASSINDATA& operator=(const IOCPPASSINDATA& other) {
if (this != &other) {
std::memset(&overlapped, 0, sizeof(overlapped));
event = other.event;
socket = other.socket;
ssl = other.ssl;
transferredbytes = other.transferredbytes;
bufsize = other.bufsize;
IOCPInstance = other.IOCPInstance;
@@ -121,7 +123,10 @@ struct IOCPPASSINDATA {
std::memcpy(wsabuf.buf, other.wsabuf.buf, other.wsabuf.len);
}
return *this;
}
}*/
IOCPPASSINDATA(const IOCPPASSINDATA& other) = delete;
IOCPPASSINDATA& operator=(const IOCPPASSINDATA&) = delete;
};
class IOCP {

21
include/socket/packet.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include <cstdint>
namespace Packet {
enum class Opcode {
NOP,
SPAWNMODEL,
DESPAWNMODEL,
UPDATEMODEL,
REQUESTMODELIDLIST,
COUNT
};
struct Header {
Opcode opcode;
std::uint32_t body_length;
};
} // namespace Packet

View File

@@ -16,6 +16,13 @@ struct Snowflake {
bool operator==(const Snowflake& other) const {
return snowflake == other.snowflake;
}
std::vector<char> Serialize() {
std::vector<char> serialized;
serialized.insert(serialized.end(), &snowflake,
&snowflake + sizeof(std::uint64_t));
return serialized;
}
};
Snowflake GenerateID();

View File

@@ -7,6 +7,7 @@
#include "material.h"
#include "vulkan_engine/vulkan/buffer_handle.h"
#include "vulkan_engine/vulkan/vertex.h"
#include "utils/snowflake.h"
namespace veng {
struct Model {
@@ -34,6 +35,7 @@ struct Model {
OnColision(other.OnColision),
visible(other.visible),
colision(other.colision) {
ID = utils::GenerateID();
graphics_ = nullptr;
}
@@ -57,12 +59,16 @@ struct Model {
OnColision(other.OnColision),
visible(other.visible),
colision(other.colision) {
ID = other.ID;
::memset(&other.ID, 0, 64);
graphics_ = other.graphics_;
other.graphics_ = nullptr;
}
Model& operator=(const Model& other) {
if (this != &other) {
ID = utils::GenerateID();
vertices = other.vertices;
vertex_buffer = other.vertex_buffer;
indices = other.indices;
@@ -90,6 +96,8 @@ struct Model {
Model& operator=(Model&& other) noexcept {
if (this != &other) {
ID = other.ID;
::memset(&other.ID, 0, 64);
vertices = std::move(other.vertices);
vertex_buffer = other.vertex_buffer;
indices = std::move(other.indices);
@@ -110,12 +118,15 @@ struct Model {
visible = other.visible;
colision = other.colision;
// graphics_만 옮기고, 원본은 nullptr
graphics_ = other.graphics_;
other.graphics_ = nullptr;
}
return *this;
}
utils::Snowflake ID;
std::vector<char> Serialize();
void Deserialize(std::vector<char> data);
std::vector<veng::Vertex> vertices;
veng::BufferHandle vertex_buffer;