diff --git a/core/include/util/network_packet.hpp b/core/include/util/network_packet.hpp index 3b86f43a..b261f2ec 100644 --- a/core/include/util/network_packet.hpp +++ b/core/include/util/network_packet.hpp @@ -2,18 +2,55 @@ #define __PACKET_HPP__ #include -#define PACKET_SIZE (4 + (20 * 10 * 4) + (7 * 4) + 9) -#define PACKET_MAGIC 0x5041434B + +enum PacketInfo +{ + PACKET_SIZE = ((20 * 10 * 4) + (7 * 4) + 9), + BUFFER_SIZE = 1024, + PACKET_MAGIC = 0x5041434B, + PACKET_MAGIC_SIZE = 4, + PACKET_ID_SIZE = 9 +}; + +/* +serialization packet +magic 4byte +flag bit 4byte : 0 => board / 1 => type / 2 => rotation / 3 => r / 4 => c / 5 => deleted_line / 6 => is_game_over / 7 => is_win / 8 => id +data ? byte +uint8_t is_board_compressed => 1: compress, 0: non-compress +uint8_t board[20][10]; => compress len + compress data +uint8_t type; +uint8_t rotation; +uint8_t r; +uint8_t c; +uint8_t deleted_line; +uint8_t is_game_over; +uint8_t is_win; +uint8_t id_len; +char id[9]; +*/ + +enum FlagBitInfo : uint32_t +{ + BOARD_BIT = (1 << 0), + TYPE_BIT = (1 << 1), + ROTATION_BIT = (1 << 2), + R_BIT = (1 << 3), + C_BIT = (1 << 4), + DELETED_LINE_BIT = (1 << 5), + IS_GAME_OVER_BIT = (1 << 6), + IS_WIN_BIT = (1 << 7), + ID_BIT = (1 << 8) +}; typedef struct PacketStruct { - int32_t magic; int32_t board[20][10]; int32_t type; int32_t rotation; int32_t r; int32_t c; int32_t deleted_line; - int32_t is_game_over; // 1 => True, 0 => False + int32_t is_game_over; int32_t is_win; char id[9]; } Packet; diff --git a/lobby/include/lobby_network_packet.hpp b/lobby/include/lobby_network_packet.hpp index d78b7e90..05cb7ce2 100644 --- a/lobby/include/lobby_network_packet.hpp +++ b/lobby/include/lobby_network_packet.hpp @@ -2,19 +2,46 @@ #define __LOBBY_PACKET_HPP__ #include -#define USER_DATA_SIZE (4 + 13 + 4 + 4 + 101) -#define ROOM_DATA_SIZE (4 + 69 + 9 + 4 + 9 + 101) -#define IDSIZE 9 -#define MAXUSER 4 -#define ROOMNAMESIZE 9 -#define COMMENTSIZE 101 -#define USER_DATA_MAGIC 0x55534552 -#define ROOM_DATA_MAGIC 0x524F4F4D +enum LobbyPacketInfo +{ + USER_DATA_SIZE = (4 + 13 + 4 + 4 + 101), + ROOM_DATA_SIZE = (4 + 69 + 9 + 4 + 9 + 101), + LOBBY_BUFFER_SIZE = 1024, + IDSIZE = 9, + MAXUSER = 4, + ROOMNAMESIZE = 9, + COMMENTSIZE = 101, + LOBBY_MAGIC_SIZE = 4, + USER_DATA_MAGIC = 0x55534552, + ROOM_DATA_MAGIC = 0x524F4F4D +}; + +/* +serialization packet +magic 4byte +flag bit 4byte : 0 => id / 1 => is_enter / 2 => is_out / 3 => is_chat / 4 => comment +data ? byte +uint8_t id_len; +char id[IDSIZE]; +uint8_t is_enter; +uint8_t is_out; +uint8_t is_chat; +uint8_t comment_len; +char comment[COMMENTSIZE]; +*/ + +enum LobbyUserFlagBitInfo : uint32_t +{ + LOBBY_USER_ID_BIT = (1 << 0), + LOBBY_USER_IS_ENTER_BIT = (1 << 1), + LOBBY_USER_IS_OUT_BIT = (1 << 2), + LOBBY_USER_IS_CHAT_BIT = (1 << 3), + LOBBY_USER_COMMENT_BIT = (1 << 4), +}; typedef struct _user_data { - int32_t magic; char id[IDSIZE]; int32_t is_enter; int32_t is_out; @@ -22,13 +49,55 @@ typedef struct _user_data char comment[COMMENTSIZE]; } user_data; +/* +serialization packet +magic 4byte +flag bit 4byte : 0 => room_master_id / 1 => id / 2 => room_name / 3 => id_len / 4 => is_enter_not_success / 5 => is_game_start +/ 6 => is_broadcast / 7 => is_update / 8 => is_broadcast_delete / 9 => is_chat / 10 => comment_id / 11 => comment +data ? byte +uint8_t room_master_id_len; +char room_master_id[IDSIZE]; +uint8_t id_len; +[for id_len] +uint8_t user_per_id_len; +char id[MAXUSER][IDSIZE] +[end] +uint8_t room_name_len; +char room_name[ROOMNAMESIZE]; +uint8_t is_enter_not_success; +uint8_t is_game_start; +uint8_t is_broadcast; +uint8_t is_update; +uint8_t is_broadcast_delete; +uint8_t is_chat; +uint8_t comment_id_len; +char comment_id[IDSIZE]; +uint8_t comment_len; +char comment[COMMENTSIZE]; +*/ + +enum LobbyRoomFlagBitInfo : uint32_t +{ + LOBBY_ROOM_ROOM_MASTER_ID_BIT = (1 << 0), + LOBBY_ROOM_ID_BIT = (1 << 1), + LOBBY_ROOM_ROOM_NAME_BIT = (1 << 2), + LOBBY_ROOM_ID_LEN_BIT = (1 << 3), + LOBBY_ROOM_IS_ENTER_NOT_SUCCESS_BIT = (1 << 4), + LOBBY_ROOM_IS_GAME_START_BIT = (1 << 5), + LOBBY_ROOM_IS_BROADCAST_BIT = (1 << 6), + LOBBY_ROOM_IS_UPDATE_BIT = (1 << 7), + LOBBY_ROOM_IS_BROADCAST_DELETE_BIT = (1 << 8), + LOBBY_ROOM_IS_CHAT_BIT = (1 << 9), + LOBBY_ROOM_COMMENT_ID_BIT = (1 << 10), + LOBBY_ROOM_COMMENT_BIT = (1 << 11) +}; + typedef struct _room_data { - int32_t magic; char room_master_id[IDSIZE]; + int32_t id_len; char id[MAXUSER][IDSIZE]; char room_name[ROOMNAMESIZE]; - int32_t id_len; int32_t is_enter_not_success; int32_t is_game_start; int32_t is_broadcast; diff --git a/lobby/source/lobby.cpp b/lobby/source/lobby.cpp index b183990c..a9c7eee4 100644 --- a/lobby/source/lobby.cpp +++ b/lobby/source/lobby.cpp @@ -183,7 +183,7 @@ bool Lobby::waiting_client() } memset(ip, 16, sizeof(ip)); - user_data received_data; + user_data received_data{}; if (network->recv_udp(received_data, ip) == false) continue; if (index >= 4 || @@ -309,7 +309,7 @@ bool Lobby::enter_lobby() } memset(room_ip, 16, sizeof(room_ip)); - room_data received_data; + room_data received_data{}; if (network->recv_udp(received_data, room_ip) == false) continue; if (received_data.is_broadcast && diff --git a/platform/linux/include/lobby_network/linux_lobby_network.hpp b/platform/linux/include/lobby_network/linux_lobby_network.hpp index 2aeaa063..f5b0a6bf 100644 --- a/platform/linux/include/lobby_network/linux_lobby_network.hpp +++ b/platform/linux/include/lobby_network/linux_lobby_network.hpp @@ -24,12 +24,19 @@ class LinuxLobbyNetwork : public ILobbyNetwork int32_t read_32b(const uint8_t*& p); void read_bytes(const uint8_t*& p, void* dst, size_t size); + void compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, uint32_t bit_check); + void compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, size_t size, + uint32_t bit_check); + void decompress_32b(const uint8_t*& p, int32_t& v); + void decompress_bytes(const uint8_t*& p, void* data, size_t size); + // user_data - void serialize(uint8_t* buf, const user_data& pkt); - void deserialize(const uint8_t* buf, user_data& pkt); + uint32_t serialize(uint8_t* buf, const user_data& pkt); + bool deserialize(const uint8_t* buf, user_data& pkt); // room_data - void serialize(uint8_t* buf, const room_data& pkt); - void deserialize(const uint8_t* buf, room_data& pkt); + uint32_t serialize(uint8_t* buf, const room_data& pkt); + bool deserialize(const uint8_t* buf, room_data& pkt); + public: LinuxLobbyNetwork(); void find_broadcast_ip(char* broadcast_ip) override; diff --git a/platform/linux/include/network/linux_network.hpp b/platform/linux/include/network/linux_network.hpp index 25a5975e..59cb0d86 100644 --- a/platform/linux/include/network/linux_network.hpp +++ b/platform/linux/include/network/linux_network.hpp @@ -22,10 +22,17 @@ class LinuxNetwork : public INetwork void write_32b(uint8_t*& p, int32_t v); void write_bytes(uint8_t*& p, const void* data, size_t size); - void serialize(uint8_t* buf, const Packet& pkt); int32_t read_32b(const uint8_t*& p); void read_bytes(const uint8_t*& p, void* dst, size_t size); - void deserialize(const uint8_t* buf, Packet& pkt); + + void compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, uint32_t bit_check); + void compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, size_t size, + uint32_t bit_check); + void decompress_32b(const uint8_t*& p, int32_t& v); + void decompress_bytes(const uint8_t*& p, void* data, size_t size); + + uint32_t serialize(uint8_t* buf, const Packet& pkt); + bool deserialize(const uint8_t* buf, Packet& pkt); public: LinuxNetwork(); diff --git a/platform/linux/source/lobby_network/linux_lobby_network.cpp b/platform/linux/source/lobby_network/linux_lobby_network.cpp index 64ae04a5..94888fc5 100644 --- a/platform/linux/source/lobby_network/linux_lobby_network.cpp +++ b/platform/linux/source/lobby_network/linux_lobby_network.cpp @@ -114,76 +114,211 @@ void LinuxLobbyNetwork::read_bytes(const uint8_t*& p, void* dst, size_t size) p += size; } +void LinuxLobbyNetwork::compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, + uint32_t bit_check) +{ + uint8_t itc = 0; + + flag_bit |= bit_check; + itc = static_cast(v); + write_bytes(p, &itc, 1); +} + +void LinuxLobbyNetwork::compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, + size_t size, uint32_t bit_check) +{ + flag_bit |= bit_check; + write_bytes(p, data, size); +} + +void LinuxLobbyNetwork::decompress_32b(const uint8_t*& p, int32_t& v) +{ + uint8_t itc; + read_bytes(p, &itc, 1); + v = static_cast(itc); +} + +void LinuxLobbyNetwork::decompress_bytes(const uint8_t*& p, void* data, size_t size) +{ + read_bytes(p, data, size); +} + // user_data -void LinuxLobbyNetwork::serialize(uint8_t* buf, const user_data& pkt) +uint32_t LinuxLobbyNetwork::serialize(uint8_t* buf, const user_data& pkt) { uint8_t* p = buf; + uint8_t* op = buf; + uint32_t flag_bit = 0; + uint8_t len = 0; - write_32b(p, pkt.magic); - write_bytes(p, pkt.id, 9); - write_32b(p, pkt.is_enter); - write_32b(p, pkt.is_out); - write_32b(p, pkt.is_chat); - write_bytes(p, pkt.comment, 101); + write_32b(p, USER_DATA_MAGIC); + op += 4; + + // flag bit + p += 4; + + len = static_cast(strlen(pkt.id)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_USER_ID_BIT); + compress_bytes(p, flag_bit, pkt.id, len, LOBBY_USER_ID_BIT); + + if (pkt.is_enter == 1) compress_32b(p, flag_bit, pkt.is_enter, LOBBY_USER_IS_ENTER_BIT); + if (pkt.is_out == 1) compress_32b(p, flag_bit, pkt.is_out, LOBBY_USER_IS_OUT_BIT); + if (pkt.is_chat == 1) compress_32b(p, flag_bit, pkt.is_chat, LOBBY_USER_IS_CHAT_BIT); + + len = static_cast(strlen(pkt.comment)); + if (len > 0) { + compress_bytes(p, flag_bit, &len, 1, LOBBY_USER_COMMENT_BIT); + compress_bytes(p, flag_bit, pkt.comment, len, LOBBY_USER_COMMENT_BIT); + } + + write_32b(op, flag_bit); + + return (p - buf); } -void LinuxLobbyNetwork::deserialize(const uint8_t* buf, user_data& pkt) +bool LinuxLobbyNetwork::deserialize(const uint8_t* buf, user_data& pkt) { const uint8_t* p = buf; + uint32_t magic = 0; + uint32_t flag_bit = 0; + uint8_t len = 0; + + magic = read_32b(p); + if (magic != USER_DATA_MAGIC) return false; + + flag_bit = read_32b(p); + + memset((void*) &pkt, 0, USER_DATA_SIZE); + + if (flag_bit & LOBBY_USER_ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.id, len); + pkt.id[len] = '\0'; + } + if (flag_bit & LOBBY_USER_IS_ENTER_BIT) decompress_32b(p, pkt.is_enter); + if (flag_bit & LOBBY_USER_IS_OUT_BIT) decompress_32b(p, pkt.is_out); + if (flag_bit & LOBBY_USER_IS_CHAT_BIT) decompress_32b(p, pkt.is_chat); + if (flag_bit & LOBBY_USER_COMMENT_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.comment, len); + pkt.comment[len] = '\0'; + } - pkt.magic = read_32b(p); - read_bytes(p, pkt.id, 9); - pkt.id[8] = '\0'; - pkt.is_enter = read_32b(p); - pkt.is_out = read_32b(p); - pkt.is_chat = read_32b(p); - read_bytes(p, pkt.comment, 101); + return true; } // room_data -void LinuxLobbyNetwork::serialize(uint8_t* buf, const room_data& pkt) +uint32_t LinuxLobbyNetwork::serialize(uint8_t* buf, const room_data& pkt) { uint8_t* p = buf; + uint8_t* op = buf; + uint32_t flag_bit = 0; + uint8_t len = 0; + + write_32b(p, ROOM_DATA_MAGIC); + op += 4; + + // flag bit + p += 4; - write_32b(p, pkt.magic); - write_bytes(p, pkt.room_master_id, 9); - for (int i = 0; i < 4; ++i) - { - write_bytes(p, pkt.id[i], 9); + len = static_cast(strlen(pkt.room_master_id)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_ROOM_MASTER_ID_BIT); + compress_bytes(p, flag_bit, pkt.room_master_id, len, LOBBY_ROOM_ROOM_MASTER_ID_BIT); + + if (pkt.id_len > 0) { + compress_32b(p, flag_bit, pkt.id_len, LOBBY_ROOM_ID_LEN_BIT); + for (int i = 0; i < pkt.id_len; ++i) { + len = static_cast(strlen(pkt.id[i])); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_ID_BIT); + compress_bytes(p, flag_bit, pkt.id[i], len, LOBBY_ROOM_ID_BIT); + } } - write_bytes(p, pkt.room_name, 9); - write_32b(p, pkt.id_len); - write_32b(p, pkt.is_enter_not_success); - write_32b(p, pkt.is_game_start); - write_32b(p, pkt.is_broadcast); - write_32b(p, pkt.is_update); - write_32b(p, pkt.is_broadcast_delete); - write_32b(p, pkt.is_chat); - write_bytes(p, pkt.comment_id, 9); - write_bytes(p, pkt.comment, 101); + + len = static_cast(strlen(pkt.room_name)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_ROOM_NAME_BIT); + compress_bytes(p, flag_bit, pkt.room_name, len, LOBBY_ROOM_ROOM_NAME_BIT); + + if (pkt.is_enter_not_success == 1) + compress_32b(p, flag_bit, pkt.is_enter_not_success, LOBBY_ROOM_IS_ENTER_NOT_SUCCESS_BIT); + if (pkt.is_game_start == 1) + compress_32b(p, flag_bit, pkt.is_game_start, LOBBY_ROOM_IS_GAME_START_BIT); + if (pkt.is_broadcast == 1) + compress_32b(p, flag_bit, pkt.is_broadcast, LOBBY_ROOM_IS_BROADCAST_BIT); + if (pkt.is_update == 1) compress_32b(p, flag_bit, pkt.is_update, LOBBY_ROOM_IS_UPDATE_BIT); + if (pkt.is_broadcast_delete == 1) + compress_32b(p, flag_bit, pkt.is_broadcast_delete, LOBBY_ROOM_IS_BROADCAST_DELETE_BIT); + if (pkt.is_chat == 1) compress_32b(p, flag_bit, pkt.is_chat, LOBBY_ROOM_IS_CHAT_BIT); + + if (pkt.is_chat == 1) { + len = static_cast(strlen(pkt.comment_id)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_COMMENT_ID_BIT); + compress_bytes(p, flag_bit, pkt.comment_id, len, LOBBY_ROOM_COMMENT_ID_BIT); + len = static_cast(strlen(pkt.comment)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_COMMENT_BIT); + compress_bytes(p, flag_bit, pkt.comment, len, LOBBY_ROOM_COMMENT_BIT); + } + + write_32b(op, flag_bit); + + return (p - buf); } -void LinuxLobbyNetwork::deserialize(const uint8_t* buf, room_data& pkt) +bool LinuxLobbyNetwork::deserialize(const uint8_t* buf, room_data& pkt) { const uint8_t* p = buf; + uint32_t magic = 0; + uint32_t flag_bit = 0; + uint8_t len = 0; + + magic = read_32b(p); + if (magic != ROOM_DATA_MAGIC) return false; + + flag_bit = read_32b(p); + + memset((void*) &pkt, 0, ROOM_DATA_SIZE); - pkt.magic = read_32b(p); - read_bytes(p, pkt.room_master_id, 9); - pkt.room_master_id[8] = '\0'; - for (int i = 0; i < 4; ++i) { - read_bytes(p, pkt.id[i], 9); - pkt.id[i][8] = '\0'; + if (flag_bit & LOBBY_ROOM_ROOM_MASTER_ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.room_master_id, len); + pkt.room_master_id[len] = '\0'; } - read_bytes(p, pkt.room_name, 9); - pkt.id_len = read_32b(p); - pkt.is_enter_not_success = read_32b(p); - pkt.is_game_start = read_32b(p); - pkt.is_broadcast = read_32b(p); - pkt.is_update = read_32b(p); - pkt.is_broadcast_delete = read_32b(p); - pkt.is_chat = read_32b(p); - read_bytes(p, pkt.comment_id, 9); - read_bytes(p, pkt.comment, 101); + + if (flag_bit & LOBBY_ROOM_ID_LEN_BIT) decompress_32b(p, pkt.id_len); + + if (flag_bit & LOBBY_ROOM_ID_BIT) { + for (int i = 0; i < pkt.id_len; ++i) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.id[i], len); + pkt.id[i][len] = '\0'; + } + } + + if (flag_bit & LOBBY_ROOM_ROOM_NAME_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.room_name, len); + pkt.room_name[len] = '\0'; + } + + if (flag_bit & LOBBY_ROOM_IS_ENTER_NOT_SUCCESS_BIT) decompress_32b(p, pkt.is_enter_not_success); + if (flag_bit & LOBBY_ROOM_IS_GAME_START_BIT) decompress_32b(p, pkt.is_game_start); + if (flag_bit & LOBBY_ROOM_IS_BROADCAST_BIT) decompress_32b(p, pkt.is_broadcast); + if (flag_bit & LOBBY_ROOM_IS_UPDATE_BIT) decompress_32b(p, pkt.is_update); + if (flag_bit & LOBBY_ROOM_IS_BROADCAST_DELETE_BIT) decompress_32b(p, pkt.is_broadcast_delete); + if (flag_bit & LOBBY_ROOM_IS_CHAT_BIT) decompress_32b(p, pkt.is_chat); + + if (flag_bit & LOBBY_ROOM_COMMENT_ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.comment_id, len); + pkt.comment_id[len] = '\0'; + } + + if (flag_bit & LOBBY_ROOM_COMMENT_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.comment, len); + pkt.comment[len] = '\0'; + } + + return true; } void LinuxLobbyNetwork::send_udp(const char* id, int is_enter, int is_out, int is_chat, const char* comment, @@ -192,31 +327,32 @@ void LinuxLobbyNetwork::send_udp(const char* id, int is_enter, int is_out, int i sockaddr_in addr{}; int addr_len; user_data data{}; - uint8_t buf[USER_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int send_result; + uint32_t buffer_size = 0; addr_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = htons(LOBBY_PORT); inet_pton(AF_INET, send_ip, &addr.sin_addr); - data.magic = USER_DATA_MAGIC; snprintf(data.id, sizeof(data.id), "%s", id); data.is_enter = is_enter; data.is_out = is_out; data.is_chat = is_chat; snprintf(data.comment, sizeof(data.comment), "%s", comment); - serialize(buf, data); + buffer_size = serialize(buf, data); - send_result = sendto(sock, (char*) buf, USER_DATA_SIZE, 0, (sockaddr*) &addr, sizeof(addr)); + send_result = sendto(sock, (char*)buf, buffer_size, 0, (sockaddr*) &addr, sizeof(addr)); if (send_result < 0) perror("sendto failed: "); } bool LinuxLobbyNetwork::recv_udp(user_data& ud, char* ip) { socklen_t addr_len; - uint8_t buf[USER_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int recv_result; + bool is_deserialize_success = false; int n = epoll_wait(epfd, events, MAX_EVENTS, 0); if (n < 0) { @@ -242,14 +378,13 @@ bool LinuxLobbyNetwork::recv_udp(user_data& ud, char* ip) break; } } - else if (recv_result != USER_DATA_SIZE) + else if (recv_result < LOBBY_MAGIC_SIZE) break; inet_ntop(AF_INET, &addr.sin_addr, ip, 16); - deserialize(buf, ud); + is_deserialize_success = deserialize(buf, ud); - if(ud.magic != USER_DATA_MAGIC) - break; + if (is_deserialize_success == false) break; return true; } @@ -267,16 +402,16 @@ void LinuxLobbyNetwork::send_udp(const char* room_master_id, sockaddr_in addr{}; int addr_len; room_data data{}; - uint8_t buf[ROOM_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int send_result; int index = 0; + uint32_t buffer_size = 0; addr_len = sizeof(addr); addr.sin_family = AF_INET; addr.sin_port = htons(LOBBY_PORT); inet_pton(AF_INET, send_ip, &addr.sin_addr); - data.magic = ROOM_DATA_MAGIC; snprintf(data.room_master_id, sizeof(data.room_master_id), "%s", room_master_id); for (const auto& [id, ip] : ids_ips) snprintf(data.id[index++], sizeof(data.id[0]), "%s", id.c_str()); @@ -290,17 +425,18 @@ void LinuxLobbyNetwork::send_udp(const char* room_master_id, data.is_chat = is_chat; snprintf(data.comment_id, sizeof(data.comment_id), "%s", comment_id); snprintf(data.comment, sizeof(data.comment), "%s", comment); - serialize(buf, data); + buffer_size = serialize(buf, data); - send_result = sendto(sock, (char*) buf, ROOM_DATA_SIZE, 0, (sockaddr*) &addr, sizeof(addr)); + send_result = sendto(sock, (char*) buf, buffer_size, 0, (sockaddr*) &addr, sizeof(addr)); if (send_result < 0) perror("sendto failed: "); } bool LinuxLobbyNetwork::recv_udp(room_data& rd, char* ip) { socklen_t addr_len; - uint8_t buf[ROOM_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int recv_result; + bool is_deserialize_success = false; int n = epoll_wait(epfd, events, MAX_EVENTS, 0); if (n < 0) { @@ -325,14 +461,13 @@ bool LinuxLobbyNetwork::recv_udp(room_data& rd, char* ip) break; } } - else if (recv_result != ROOM_DATA_SIZE) + else if (recv_result < LOBBY_MAGIC_SIZE) break; inet_ntop(AF_INET, &addr.sin_addr, ip, 16); - deserialize(buf, rd); + is_deserialize_success = deserialize(buf, rd); - if (rd.magic != ROOM_DATA_MAGIC) - break; + if (is_deserialize_success == false) break; return true; } diff --git a/platform/linux/source/network/linux_network.cpp b/platform/linux/source/network/linux_network.cpp index cb994673..7b9eefe9 100644 --- a/platform/linux/source/network/linux_network.cpp +++ b/platform/linux/source/network/linux_network.cpp @@ -59,27 +59,6 @@ void LinuxNetwork::write_bytes(uint8_t*& p, const void* data, size_t size) p += size; } -void LinuxNetwork::serialize(uint8_t* buf, const Packet& pkt) -{ - uint8_t* p = buf; - - write_32b(p, pkt.magic); - - for (int i = 0; i < 20; ++i) - for (int j = 0; j < 10; ++j) - write_32b(p, pkt.board[i][j]); - - write_32b(p, pkt.type); - write_32b(p, pkt.rotation); - write_32b(p, pkt.r); - write_32b(p, pkt.c); - write_32b(p, pkt.deleted_line); - write_32b(p, pkt.is_game_over); - write_32b(p, pkt.is_win); - - write_bytes(p, pkt.id, 9); -} - int32_t LinuxNetwork::read_32b(const uint8_t*& p) { int32_t n; @@ -94,42 +73,168 @@ void LinuxNetwork::read_bytes(const uint8_t*& p, void* dst, size_t size) p += size; } -void LinuxNetwork::deserialize(const uint8_t* buf, Packet& pkt) +void LinuxNetwork::compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, uint32_t bit_check) { - const uint8_t* p = buf; + uint8_t itc = 0; - pkt.magic = read_32b(p); + flag_bit |= bit_check; + itc = static_cast(v); + write_bytes(p, &itc, 1); +} - for (int i = 0; i < 20; ++i) - for (int j = 0; j < 10; ++j) - pkt.board[i][j] = read_32b(p); +void LinuxNetwork::compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, size_t size, + uint32_t bit_check) +{ + flag_bit |= bit_check; + write_bytes(p, data, size); +} - pkt.type = read_32b(p); - pkt.rotation = read_32b(p); - pkt.r = read_32b(p); - pkt.c = read_32b(p); - pkt.deleted_line = read_32b(p); - pkt.is_game_over = read_32b(p); - pkt.is_win = read_32b(p); +void LinuxNetwork::decompress_32b(const uint8_t*& p, int32_t& v) +{ + uint8_t itc; + read_bytes(p, &itc, 1); + v = static_cast(itc); +} - read_bytes(p, pkt.id, 9); - pkt.id[8] = '\0'; +void LinuxNetwork::decompress_bytes(const uint8_t*& p, void* data, size_t size) +{ + read_bytes(p, data, size); +} + +uint32_t LinuxNetwork::serialize(uint8_t* buf, const Packet& pkt) +{ + uint8_t* p = buf; + uint8_t* op = buf; + uint32_t flag_bit = 0; + uint8_t len = 0; + int32_t board_block_num = 0; + int32_t board_block_type = 0; + uint8_t compress_board[400]; + uint8_t non_compress_board[200]; + uint8_t* c_board_p = compress_board; + uint8_t* n_c_board_p = non_compress_board; + + write_32b(p, PACKET_MAGIC); + op += 4; + + // flag bit + p += 4; + + board_block_type = pkt.board[0][0]; + for (int i = 0; i < 20; ++i) { + for (int j = 0; j < 10; ++j) { + if (board_block_type == pkt.board[i][j]) + board_block_num++; + else + { + compress_32b(c_board_p, flag_bit, board_block_num, BOARD_BIT); + compress_32b(c_board_p, flag_bit, board_block_type, BOARD_BIT); + board_block_num = 1; + board_block_type = pkt.board[i][j]; + } + compress_32b(n_c_board_p, flag_bit, pkt.board[i][j], BOARD_BIT); + } + } + compress_32b(c_board_p, flag_bit, board_block_num, BOARD_BIT); + compress_32b(c_board_p, flag_bit, board_block_type, BOARD_BIT); + + if (c_board_p - compress_board >= 200) + { + compress_32b(p, flag_bit, 0, BOARD_BIT); + compress_bytes(p, flag_bit, non_compress_board, 200, BOARD_BIT); + } + else + { + compress_32b(p, flag_bit, 1, BOARD_BIT); + compress_bytes(p, flag_bit, compress_board, c_board_p - compress_board, BOARD_BIT); + } + + compress_32b(p, flag_bit, pkt.type, TYPE_BIT); + compress_32b(p, flag_bit, pkt.rotation, ROTATION_BIT); + compress_32b(p, flag_bit, pkt.r, R_BIT); + compress_32b(p, flag_bit, pkt.c, C_BIT); + compress_32b(p, flag_bit, pkt.deleted_line, DELETED_LINE_BIT); + + if (pkt.is_game_over == 1) compress_32b(p, flag_bit, pkt.is_game_over, IS_GAME_OVER_BIT); + if (pkt.is_win == 1) compress_32b(p, flag_bit, pkt.is_win, IS_WIN_BIT); + + len = static_cast(strlen(pkt.id)); + compress_bytes(p, flag_bit, &len, 1, ID_BIT); + compress_bytes(p, flag_bit, pkt.id, len, ID_BIT); + + // flag bit + write_32b(op, flag_bit); + + return (p - buf); +} + +bool LinuxNetwork::deserialize(const uint8_t* buf, Packet& pkt) +{ + const uint8_t* p = buf; + uint32_t magic = 0; + uint32_t flag_bit = 0; + uint8_t len = 0; + uint32_t board_size = 200; + int32_t board_block_num = 0; + int32_t board_block_type = 0; + int32_t is_board_compressed = 0; + auto* board = &pkt.board[0][0]; + + magic = read_32b(p); + if (magic != PACKET_MAGIC) return false; + + flag_bit = read_32b(p); + + memset((void*) &pkt, 0, PACKET_SIZE); + + if (flag_bit & BOARD_BIT) { + decompress_32b(p, is_board_compressed); + + if (is_board_compressed == 1) { + while (board_size > 0) { + decompress_32b(p, board_block_num); + decompress_32b(p, board_block_type); + for (int i = 0; i < board_block_num; ++i) { + *(board++) = board_block_type; + } + board_size -= board_block_num; + } + } + else { + for (int i = 0; i < 20; ++i) + for (int j = 0; j < 10; ++j) + decompress_32b(p, pkt.board[i][j]); + } + } + if (flag_bit & TYPE_BIT) decompress_32b(p, pkt.type); + if (flag_bit & ROTATION_BIT) decompress_32b(p, pkt.rotation); + if (flag_bit & R_BIT) decompress_32b(p, pkt.r); + if (flag_bit & C_BIT) decompress_32b(p, pkt.c); + if (flag_bit & DELETED_LINE_BIT) decompress_32b(p, pkt.deleted_line); + if (flag_bit & IS_GAME_OVER_BIT) decompress_32b(p, pkt.is_game_over); + if (flag_bit & IS_WIN_BIT) decompress_32b(p, pkt.is_win); + if (flag_bit & ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.id, len); + pkt.id[len] = '\0'; + } + + return true; } void LinuxNetwork::send_udp(const Board& board, const Tetromino& tetromino, const int deleted_line, int is_game_over, int is_win, const char* another_user_ip, const char* my_id) { Packet pkt; - uint8_t buf[PACKET_SIZE]; + uint8_t buf[BUFFER_SIZE]; auto [pos_r, pos_c] = tetromino.get_pos(); sockaddr_in another_user; int send_result; + uint32_t buffer_size = 0; another_user.sin_family = AF_INET; another_user.sin_port = htons(PORT); inet_pton(AF_INET, another_user_ip, &another_user.sin_addr); - pkt.magic = PACKET_MAGIC; - for (int r = 0; r < 20; ++r) for (int c = 0; c < 10; ++c) pkt.board[r][c] = board.at(r + 2, c); @@ -143,9 +248,10 @@ void LinuxNetwork::send_udp(const Board& board, const Tetromino& tetromino, cons pkt.is_win = is_win; snprintf(pkt.id, sizeof(pkt.id), "%s", my_id); - serialize(buf, pkt); + buffer_size = serialize(buf, pkt); - send_result = sendto(client_sock, (char*) buf, PACKET_SIZE, 0, (sockaddr*) &another_user, sizeof(another_user)); + send_result = sendto(client_sock, (char*) buf, buffer_size, 0, (sockaddr*) &another_user, + sizeof(another_user)); if(send_result < 0) perror("sendto failed: "); @@ -164,8 +270,9 @@ void LinuxNetwork::send_relay_udp(const Packet& packet, std::vector> ids_ips) { char* another_user_ip; - uint8_t buf[PACKET_SIZE]; + uint8_t buf[BUFFER_SIZE]; int send_result; + uint32_t buffer_size = 0; for (const auto& [id, ip] : ids_ips) { if (strcmp(id.c_str(), packet.id) == 0) continue; @@ -178,8 +285,6 @@ void LinuxNetwork::send_relay_udp(const Packet& packet, inet_pton(AF_INET, ip.c_str(), &another_user.sin_addr); // 보드 데이터 복사 - pkt.magic = PACKET_MAGIC; - for (int r = 0; r < 20; ++r) for (int c = 0; c < 10; ++c) pkt.board[r][c] = packet.board[r][c]; // 숨겨진 2줄 제외하고 복사 @@ -193,9 +298,10 @@ void LinuxNetwork::send_relay_udp(const Packet& packet, pkt.is_win = packet.is_win; snprintf(pkt.id, sizeof(pkt.id), "%s", packet.id); - serialize(buf, pkt); + buffer_size = serialize(buf, pkt); - send_result = sendto(client_sock, (char*) buf, PACKET_SIZE, 0, (sockaddr*) &another_user, sizeof(another_user)); + send_result = sendto(client_sock, (char*) buf, buffer_size, 0, (sockaddr*) &another_user, + sizeof(another_user)); if (send_result < 0) { perror("sendto failed: "); @@ -205,8 +311,9 @@ void LinuxNetwork::send_relay_udp(const Packet& packet, bool LinuxNetwork::recv_udp(Packet& recv_pkt) { - uint8_t buf[PACKET_SIZE]; + uint8_t buf[BUFFER_SIZE]; int n = epoll_wait(epfd, events, MAX_EVENTS, 0); + bool is_deserialize_success = false; int r; if (n < 0) { @@ -221,25 +328,24 @@ bool LinuxNetwork::recv_udp(Packet& recv_pkt) sockaddr_in client{}; socklen_t len = sizeof(client); - r = recvfrom(server_sock, (char*) buf, PACKET_SIZE, 0, (sockaddr*) &client, &len); + r = recvfrom(server_sock, (char*)buf, BUFFER_SIZE, 0, (sockaddr*) &client, &len); if (r < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK) { // 수신 버퍼 비움 - break; + return false; } else { perror("recvfrom"); - break; + return false; } } - else if (r != PACKET_SIZE) - break; + else if (r < PACKET_MAGIC_SIZE) + return false; - deserialize(buf, recv_pkt); + is_deserialize_success = deserialize(buf, recv_pkt); - if (recv_pkt.magic != PACKET_MAGIC) - break; + if (is_deserialize_success == false) return false; return true; } diff --git a/platform/linux/source/render/linux_multi_renderer.cpp b/platform/linux/source/render/linux_multi_renderer.cpp index f0e06726..d2e0ab0f 100644 --- a/platform/linux/source/render/linux_multi_renderer.cpp +++ b/platform/linux/source/render/linux_multi_renderer.cpp @@ -212,7 +212,7 @@ void LinuxMultiRenderer::render_board(const Board& board, const Tetromino& tetro void LinuxMultiRenderer::render_other_board(Packet& pkt) { auto [start_x, start_y] = other_render_loc_get_or_set(std::string(pkt.id)); - auto game_board = pkt.board; + auto& game_board = pkt.board; int pos_r = pkt.r; int pos_c = pkt.c; int mino_type = pkt.type; diff --git a/platform/window/include/lobby_network/window_lobby_network.hpp b/platform/window/include/lobby_network/window_lobby_network.hpp index 7702b5b3..cbcdbce3 100644 --- a/platform/window/include/lobby_network/window_lobby_network.hpp +++ b/platform/window/include/lobby_network/window_lobby_network.hpp @@ -14,18 +14,26 @@ class WindowLobbyNetwork : public ILobbyNetwork { private: SOCKET sock; + WSAPOLLFD fds[1]; void write_32b(uint8_t*& p, int32_t v); void write_bytes(uint8_t*& p, const void* data, size_t size); int32_t read_32b(const uint8_t*& p); void read_bytes(const uint8_t*& p, void* dst, size_t size); + + void compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, uint32_t bit_check); + void compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, size_t size, + uint32_t bit_check); + void decompress_32b(const uint8_t*& p, int32_t& v); + void decompress_bytes(const uint8_t*& p, void* data, size_t size); // user_data - void serialize(uint8_t* buf, const user_data& pkt); - void deserialize(const uint8_t* buf, user_data& pkt); + uint32_t serialize(uint8_t* buf, const user_data& pkt); + bool deserialize(const uint8_t* buf, user_data& pkt); // room_data - void serialize(uint8_t* buf, const room_data& pkt); - void deserialize(const uint8_t* buf, room_data& pkt); + uint32_t serialize(uint8_t* buf, const room_data& pkt); + bool deserialize(const uint8_t* buf, room_data& pkt); + public: WindowLobbyNetwork(); void find_broadcast_ip(char* broadcast_ip) override; diff --git a/platform/window/include/network/window_network.hpp b/platform/window/include/network/window_network.hpp index 3a7be611..4fc9d015 100644 --- a/platform/window/include/network/window_network.hpp +++ b/platform/window/include/network/window_network.hpp @@ -19,19 +19,26 @@ class WindowNetwork : public INetwork SOCKET client_sock; SOCKET server_sock; - // [window] epoll 관련 변수(epfd, events)는 삭제했습니다. - // 대신 수신 주소 정보를 저장할 구조체를 미리 선언해두면 편합니다. SOCKADDR_IN server_addr; SOCKADDR_IN client_addr; + WSAPOLLFD fds[1]; + void write_32b(uint8_t*& p, int32_t v); void write_bytes(uint8_t*& p, const void* data, size_t size); - void serialize(uint8_t* buf, const Packet& pkt); int32_t read_32b(const uint8_t*& p); void read_bytes(const uint8_t*& p, void* dst, size_t size); - void deserialize(const uint8_t* buf, Packet& pkt); + + void compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, uint32_t bit_check); + void compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, + size_t size, uint32_t bit_check); + void decompress_32b(const uint8_t*& p, int32_t& v); + void decompress_bytes(const uint8_t*& p, void* data, size_t size); + + uint32_t serialize(uint8_t* buf, const Packet& pkt); + bool deserialize(const uint8_t* buf, Packet& pkt); -public: + public: WindowNetwork(); // 부모 클래스(INetwork)의 가상 함수 오버라이드 diff --git a/platform/window/source/lobby_network/window_lobby_network.cpp b/platform/window/source/lobby_network/window_lobby_network.cpp index 33183cf0..c6506b27 100644 --- a/platform/window/source/lobby_network/window_lobby_network.cpp +++ b/platform/window/source/lobby_network/window_lobby_network.cpp @@ -46,6 +46,10 @@ WindowLobbyNetwork::WindowLobbyNetwork() perror("bind failed: "); exit(0); } + + // 8. Poll + fds[0].fd = sock; + fds[0].events = POLLIN; } /** @@ -133,76 +137,212 @@ void WindowLobbyNetwork::read_bytes(const uint8_t*& p, void* dst, size_t size) p += size; } +void WindowLobbyNetwork::compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, + uint32_t bit_check) +{ + uint8_t itc = 0; + + flag_bit |= bit_check; + itc = static_cast(v); + write_bytes(p, &itc, 1); +} + +void WindowLobbyNetwork::compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, + size_t size, uint32_t bit_check) +{ + flag_bit |= bit_check; + write_bytes(p, data, size); +} + +void WindowLobbyNetwork::decompress_32b(const uint8_t*& p, int32_t& v) +{ + uint8_t itc; + read_bytes(p, &itc, 1); + v = static_cast(itc); +} + +void WindowLobbyNetwork::decompress_bytes(const uint8_t*& p, void* data, size_t size) +{ + read_bytes(p, data, size); +} + // user_data -void WindowLobbyNetwork::serialize(uint8_t* buf, const user_data& pkt) +uint32_t WindowLobbyNetwork::serialize(uint8_t* buf, const user_data& pkt) { uint8_t* p = buf; + uint8_t* op = buf; + uint32_t flag_bit = 0; + uint8_t len = 0; + + write_32b(p, USER_DATA_MAGIC); + op += 4; + + // flag bit + p += 4; + + len = static_cast(strlen(pkt.id)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_USER_ID_BIT); + compress_bytes(p, flag_bit, pkt.id, len, LOBBY_USER_ID_BIT); + + if (pkt.is_enter == 1) compress_32b(p, flag_bit, pkt.is_enter, LOBBY_USER_IS_ENTER_BIT); + if (pkt.is_out == 1) compress_32b(p, flag_bit, pkt.is_out, LOBBY_USER_IS_OUT_BIT); + if (pkt.is_chat == 1) compress_32b(p, flag_bit, pkt.is_chat, LOBBY_USER_IS_CHAT_BIT); + + len = static_cast(strlen(pkt.comment)); + if (len > 0) { + compress_bytes(p, flag_bit, &len, 1, LOBBY_USER_COMMENT_BIT); + compress_bytes(p, flag_bit, pkt.comment, len, LOBBY_USER_COMMENT_BIT); + } + + write_32b(op, flag_bit); - write_32b(p, pkt.magic); - write_bytes(p, pkt.id, 9); - write_32b(p, pkt.is_enter); - write_32b(p, pkt.is_out); - write_32b(p, pkt.is_chat); - write_bytes(p, pkt.comment, 101); + return (p - buf); } -void WindowLobbyNetwork::deserialize(const uint8_t* buf, user_data& pkt) +bool WindowLobbyNetwork::deserialize(const uint8_t* buf, user_data& pkt) { const uint8_t* p = buf; + uint32_t magic = 0; + uint32_t flag_bit = 0; + uint8_t len = 0; + + magic = read_32b(p); + if (magic != USER_DATA_MAGIC) return false; + + flag_bit = read_32b(p); + + memset((void*) &pkt, 0, USER_DATA_SIZE); - pkt.magic = read_32b(p); - read_bytes(p, pkt.id, 9); - pkt.id[8] = '\0'; - pkt.is_enter = read_32b(p); - pkt.is_out = read_32b(p); - pkt.is_chat = read_32b(p); - read_bytes(p, pkt.comment, 101); + if (flag_bit & LOBBY_USER_ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.id, len); + pkt.id[len] = '\0'; + } + if (flag_bit & LOBBY_USER_IS_ENTER_BIT) decompress_32b(p, pkt.is_enter); + if (flag_bit & LOBBY_USER_IS_OUT_BIT) decompress_32b(p, pkt.is_out); + if (flag_bit & LOBBY_USER_IS_CHAT_BIT) decompress_32b(p, pkt.is_chat); + if (flag_bit & LOBBY_USER_COMMENT_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.comment, len); + pkt.comment[len] = '\0'; + } + + return true; } // room_data -void WindowLobbyNetwork::serialize(uint8_t* buf, const room_data& pkt) +uint32_t WindowLobbyNetwork::serialize(uint8_t* buf, const room_data& pkt) { uint8_t* p = buf; - - write_32b(p, pkt.magic); - write_bytes(p, pkt.room_master_id, 9); - for (int i = 0; i < 4; ++i) - { - write_bytes(p, pkt.id[i], 9); + uint8_t* op = buf; + uint32_t flag_bit = 0; + uint8_t len = 0; + + write_32b(p, ROOM_DATA_MAGIC); + op += 4; + + // flag bit + p += 4; + + len = static_cast(strlen(pkt.room_master_id)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_ROOM_MASTER_ID_BIT); + compress_bytes(p, flag_bit, pkt.room_master_id, len, LOBBY_ROOM_ROOM_MASTER_ID_BIT); + + if (pkt.id_len > 0) { + compress_32b(p, flag_bit, pkt.id_len, LOBBY_ROOM_ID_LEN_BIT); + for (int i = 0; i < pkt.id_len; ++i) { + len = static_cast(strlen(pkt.id[i])); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_ID_BIT); + compress_bytes(p, flag_bit, pkt.id[i], len, LOBBY_ROOM_ID_BIT); + } + } + + len = static_cast(strlen(pkt.room_name)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_ROOM_NAME_BIT); + compress_bytes(p, flag_bit, pkt.room_name, len, LOBBY_ROOM_ROOM_NAME_BIT); + + if (pkt.is_enter_not_success == 1) + compress_32b(p, flag_bit, pkt.is_enter_not_success, LOBBY_ROOM_IS_ENTER_NOT_SUCCESS_BIT); + if (pkt.is_game_start == 1) + compress_32b(p, flag_bit, pkt.is_game_start, LOBBY_ROOM_IS_GAME_START_BIT); + if (pkt.is_broadcast == 1) + compress_32b(p, flag_bit, pkt.is_broadcast, LOBBY_ROOM_IS_BROADCAST_BIT); + if (pkt.is_update == 1) compress_32b(p, flag_bit, pkt.is_update, LOBBY_ROOM_IS_UPDATE_BIT); + if (pkt.is_broadcast_delete == 1) + compress_32b(p, flag_bit, pkt.is_broadcast_delete, LOBBY_ROOM_IS_BROADCAST_DELETE_BIT); + if (pkt.is_chat == 1) + compress_32b(p, flag_bit, pkt.is_chat, LOBBY_ROOM_IS_CHAT_BIT); + + if (pkt.is_chat == 1) { + len = static_cast(strlen(pkt.comment_id)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_COMMENT_ID_BIT); + compress_bytes(p, flag_bit, pkt.comment_id, len, LOBBY_ROOM_COMMENT_ID_BIT); + len = static_cast(strlen(pkt.comment)); + compress_bytes(p, flag_bit, &len, 1, LOBBY_ROOM_COMMENT_BIT); + compress_bytes(p, flag_bit, pkt.comment, len, LOBBY_ROOM_COMMENT_BIT); } - write_bytes(p, pkt.room_name, 9); - write_32b(p, pkt.id_len); - write_32b(p, pkt.is_enter_not_success); - write_32b(p, pkt.is_game_start); - write_32b(p, pkt.is_broadcast); - write_32b(p, pkt.is_update); - write_32b(p, pkt.is_broadcast_delete); - write_32b(p, pkt.is_chat); - write_bytes(p, pkt.comment_id, 9); - write_bytes(p, pkt.comment, 101); + + write_32b(op, flag_bit); + + return (p - buf); } -void WindowLobbyNetwork::deserialize(const uint8_t* buf, room_data& pkt) +bool WindowLobbyNetwork::deserialize(const uint8_t* buf, room_data& pkt) { const uint8_t* p = buf; + uint32_t magic = 0; + uint32_t flag_bit = 0; + uint8_t len = 0; + + magic = read_32b(p); + if (magic != ROOM_DATA_MAGIC) return false; + + flag_bit = read_32b(p); + + memset((void*) &pkt, 0, ROOM_DATA_SIZE); + + if (flag_bit & LOBBY_ROOM_ROOM_MASTER_ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.room_master_id, len); + pkt.room_master_id[len] = '\0'; + } + + if (flag_bit & LOBBY_ROOM_ID_LEN_BIT) decompress_32b(p, pkt.id_len); + + if (flag_bit & LOBBY_ROOM_ID_BIT) { + for (int i = 0; i < pkt.id_len; ++i) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.id[i], len); + pkt.id[i][len] = '\0'; + } + } - pkt.magic = read_32b(p); - read_bytes(p, pkt.room_master_id, 9); - pkt.room_master_id[8] = '\0'; - for (int i = 0; i < 4; ++i) { - read_bytes(p, pkt.id[i], 9); - pkt.id[i][8] = '\0'; + if (flag_bit & LOBBY_ROOM_ROOM_NAME_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.room_name, len); + pkt.room_name[len] = '\0'; } - read_bytes(p, pkt.room_name, 9); - pkt.id_len = read_32b(p); - pkt.is_enter_not_success = read_32b(p); - pkt.is_game_start = read_32b(p); - pkt.is_broadcast = read_32b(p); - pkt.is_update = read_32b(p); - pkt.is_broadcast_delete = read_32b(p); - pkt.is_chat = read_32b(p); - read_bytes(p, pkt.comment_id, 9); - read_bytes(p, pkt.comment, 101); + + if (flag_bit & LOBBY_ROOM_IS_ENTER_NOT_SUCCESS_BIT) decompress_32b(p, pkt.is_enter_not_success); + if (flag_bit & LOBBY_ROOM_IS_GAME_START_BIT) decompress_32b(p, pkt.is_game_start); + if (flag_bit & LOBBY_ROOM_IS_BROADCAST_BIT) decompress_32b(p, pkt.is_broadcast); + if (flag_bit & LOBBY_ROOM_IS_UPDATE_BIT) decompress_32b(p, pkt.is_update); + if (flag_bit & LOBBY_ROOM_IS_BROADCAST_DELETE_BIT) decompress_32b(p, pkt.is_broadcast_delete); + if (flag_bit & LOBBY_ROOM_IS_CHAT_BIT) decompress_32b(p, pkt.is_chat); + + if (flag_bit & LOBBY_ROOM_COMMENT_ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.comment_id, len); + pkt.comment_id[len] = '\0'; + } + + if (flag_bit & LOBBY_ROOM_COMMENT_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.comment, len); + pkt.comment[len] = '\0'; + } + + return true; } void WindowLobbyNetwork::send_udp(const char* id, int is_enter, int is_out, int is_chat, const char* comment, @@ -211,8 +351,9 @@ void WindowLobbyNetwork::send_udp(const char* id, int is_enter, int is_out, int SOCKADDR_IN addr; int addr_len; user_data data{}; - uint8_t buf[USER_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int send_result; + uint32_t buffer_size = 0; ZeroMemory(&addr, sizeof(addr)); addr_len = sizeof(addr); @@ -220,16 +361,15 @@ void WindowLobbyNetwork::send_udp(const char* id, int is_enter, int is_out, int addr.sin_port = htons(LOBBY_PORT); inet_pton(AF_INET, send_ip, &addr.sin_addr); - data.magic = USER_DATA_MAGIC; snprintf(data.id, sizeof(data.id), "%s", id); data.is_enter = is_enter; data.is_out = is_out; data.is_chat = is_chat; snprintf(data.comment, sizeof(data.comment), "%s", comment); - serialize(buf, data); + buffer_size = serialize(buf, data); - send_result = sendto(sock, (char*) buf, USER_DATA_SIZE, 0, (SOCKADDR*) &addr, - sizeof(addr)); + send_result = sendto(sock, (char*)buf, buffer_size, 0, (SOCKADDR*) &addr, + sizeof(addr)); if (send_result == SOCKET_ERROR) printf("sendto failed: %d\n", send_result); } @@ -237,36 +377,42 @@ bool WindowLobbyNetwork::recv_udp(user_data& ud, char* ip) { SOCKADDR_IN addr; int addr_len; - uint8_t buf[USER_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int recv_result; - int recv_err; + bool data_received = false; + bool is_deserialize_success = false; ZeroMemory(&addr, sizeof(addr)); addr_len = sizeof(addr); memset(buf, 0, sizeof(buf)); - - recv_result = recvfrom(sock, (char*) buf, sizeof(buf), 0, (SOCKADDR*) &addr, &addr_len); - recv_err = (recv_result == SOCKET_ERROR) ? WSAGetLastError() : 0; - if (recv_result == SOCKET_ERROR) { - if (recv_err == WSAEWOULDBLOCK || recv_err == WSAEMSGSIZE) - // ̻ Ͱ ( ) - return false; - else { - // ¥ ߻ - printf("recvfrom failed: %d\n", recv_err); - return false; - } - } - else if (recv_result != USER_DATA_SIZE) - return false; - inet_ntop(AF_INET, &addr.sin_addr, ip, 16); - deserialize(buf, ud); + // [window Poll ó] + int ret = WSAPoll(fds, 1, 0); - if (ud.magic != USER_DATA_MAGIC) - return false; + if (ret > 0) { + if (fds[0].revents & POLLIN) { + recv_result = recvfrom(sock, (char*) buf, sizeof(buf), 0, (SOCKADDR*) &addr, + &addr_len); - return true; + if (recv_result == SOCKET_ERROR) { + int err = WSAGetLastError(); + printf("recvfrom failed: %d\n", err); + return false; + } + else if (recv_result < LOBBY_MAGIC_SIZE) + return false; + + // + inet_ntop(AF_INET, &addr.sin_addr, ip, 16); + is_deserialize_success = deserialize(buf, ud); + + if (is_deserialize_success == false) data_received = false; + + data_received = true; + } + } + + return data_received; } void WindowLobbyNetwork::send_udp(const char* room_master_id, @@ -279,9 +425,10 @@ void WindowLobbyNetwork::send_udp(const char* room_master_id, SOCKADDR_IN addr; int addr_len; room_data data{}; - uint8_t buf[ROOM_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int send_result; int index = 0; + uint32_t buffer_size = 0; ZeroMemory(&addr, sizeof(addr)); addr_len = sizeof(addr); @@ -289,7 +436,6 @@ void WindowLobbyNetwork::send_udp(const char* room_master_id, addr.sin_port = htons(LOBBY_PORT); inet_pton(AF_INET, send_ip, &addr.sin_addr); - data.magic = ROOM_DATA_MAGIC; snprintf(data.room_master_id, sizeof(data.room_master_id), "%s", room_master_id); for (const auto& [id, ip] : ids_ips) snprintf(data.id[index++], sizeof(data.id[0]), "%s", id.c_str()); @@ -303,9 +449,9 @@ void WindowLobbyNetwork::send_udp(const char* room_master_id, data.is_chat = is_chat; snprintf(data.comment_id, sizeof(data.comment_id), "%s", comment_id); snprintf(data.comment, sizeof(data.comment), "%s", comment); - serialize(buf, data); + buffer_size = serialize(buf, data); - send_result = sendto(sock, (char*) buf, ROOM_DATA_SIZE, 0, (SOCKADDR*) &addr, sizeof(addr)); + send_result = sendto(sock, (char*)buf, buffer_size, 0, (SOCKADDR*) &addr, sizeof(addr)); if (send_result == SOCKET_ERROR) printf("sendto failed: %d\n", send_result); } @@ -313,36 +459,41 @@ bool WindowLobbyNetwork::recv_udp(room_data& rd, char* ip) { SOCKADDR_IN addr; int addr_len; - uint8_t buf[ROOM_DATA_SIZE]; + uint8_t buf[LOBBY_BUFFER_SIZE]; int recv_result; - int recv_err; + bool data_received = false; + bool is_deserialize_success = false; ZeroMemory(&addr, sizeof(addr)); addr_len = sizeof(addr); memset(buf, 0, sizeof(buf)); - recv_result = recvfrom(sock, (char*) buf, sizeof(buf), 0, (SOCKADDR*) &addr, &addr_len); - recv_err = (recv_result == SOCKET_ERROR) ? WSAGetLastError() : 0; - if (recv_result == SOCKET_ERROR) { - if (recv_err == WSAEWOULDBLOCK || recv_err == WSAEMSGSIZE) - // ̻ Ͱ ( ) - return false; - else { - // ¥ ߻ - printf("recvfrom failed: %d\n", recv_err); - return false; - } - } - else if (recv_result != ROOM_DATA_SIZE) - return false; + // [window Poll ó] + int ret = WSAPoll(fds, 1, 0); - inet_ntop(AF_INET, &addr.sin_addr, ip, 16); - deserialize(buf, rd); + if (ret > 0) { + if (fds[0].revents & POLLIN) { + recv_result = recvfrom(sock, (char*) buf, sizeof(buf), 0, (SOCKADDR*) &addr, &addr_len); - if (rd.magic != ROOM_DATA_MAGIC) - return false; + if (recv_result == SOCKET_ERROR) { + int err = WSAGetLastError(); + printf("recvfrom failed: %d\n", err); + return false; + } + else if (recv_result < LOBBY_MAGIC_SIZE) + return false; - return true; + // + inet_ntop(AF_INET, &addr.sin_addr, ip, 16); + is_deserialize_success = deserialize(buf, rd); + + if (is_deserialize_success == false) data_received = false; + + data_received = true; + } + } + + return data_received; } void WindowLobbyNetwork::send_multi_udp( diff --git a/platform/window/source/network/window_network.cpp b/platform/window/source/network/window_network.cpp index 09c7731c..a610f4bc 100644 --- a/platform/window/source/network/window_network.cpp +++ b/platform/window/source/network/window_network.cpp @@ -51,8 +51,9 @@ WindowNetwork::WindowNetwork() exit(0); } - // window에는 epoll이 없으므로 epoll 생성 코드는 삭제됩니다. - // 대신 recv_udp에서 논블로킹 소켓의 특성을 이용합니다. + // 6. Poll + fds[0].fd = server_sock; + fds[0].events = POLLIN; } void WindowNetwork::write_32b(uint8_t*& p, int32_t v) @@ -68,27 +69,6 @@ void WindowNetwork::write_bytes(uint8_t*& p, const void* data, size_t size) p += size; } -void WindowNetwork::serialize(uint8_t* buf, const Packet& pkt) -{ - uint8_t* p = buf; - - write_32b(p, pkt.magic); - - for (int i = 0; i < 20; ++i) - for (int j = 0; j < 10; ++j) - write_32b(p, pkt.board[i][j]); - - write_32b(p, pkt.type); - write_32b(p, pkt.rotation); - write_32b(p, pkt.r); - write_32b(p, pkt.c); - write_32b(p, pkt.deleted_line); - write_32b(p, pkt.is_game_over); - write_32b(p, pkt.is_win); - - write_bytes(p, pkt.id, 9); -} - int32_t WindowNetwork::read_32b(const uint8_t*& p) { int32_t n; @@ -103,26 +83,150 @@ void WindowNetwork::read_bytes(const uint8_t*& p, void* dst, size_t size) p += size; } -void WindowNetwork::deserialize(const uint8_t* buf, Packet& pkt) +void WindowNetwork::compress_32b(uint8_t*& p, uint32_t& flag_bit, int32_t v, uint32_t bit_check) { - const uint8_t* p = buf; + uint8_t itc = 0; + + flag_bit |= bit_check; + itc = static_cast(v); + write_bytes(p, &itc, 1); +} + +void WindowNetwork::compress_bytes(uint8_t*& p, uint32_t& flag_bit, const void* data, + size_t size, uint32_t bit_check) +{ + flag_bit |= bit_check; + write_bytes(p, data, size); +} + +void WindowNetwork::decompress_32b(const uint8_t*& p, int32_t& v) +{ + uint8_t itc; + read_bytes(p, &itc, 1); + v = static_cast(itc); +} + +void WindowNetwork::decompress_bytes(const uint8_t*& p, void* data, size_t size) +{ + read_bytes(p, data, size); +} + +uint32_t WindowNetwork::serialize(uint8_t* buf, const Packet& pkt) +{ + uint8_t* p = buf; + uint8_t* op = buf; + uint32_t flag_bit = 0; + uint8_t len = 0; + int32_t board_block_num = 0; + int32_t board_block_type = 0; + uint8_t compress_board[400]; + uint8_t non_compress_board[200]; + uint8_t* c_board_p = compress_board; + uint8_t* n_c_board_p = non_compress_board; + + write_32b(p, PACKET_MAGIC); + op += 4; + + // flag bit + p += 4; + + board_block_type = pkt.board[0][0]; + for (int i = 0; i < 20; ++i) { + for (int j = 0; j < 10; ++j) { + if (board_block_type == pkt.board[i][j]) + board_block_num++; + else { + compress_32b(c_board_p, flag_bit, board_block_num, BOARD_BIT); + compress_32b(c_board_p, flag_bit, board_block_type, BOARD_BIT); + board_block_num = 1; + board_block_type = pkt.board[i][j]; + } + compress_32b(n_c_board_p, flag_bit, pkt.board[i][j], BOARD_BIT); + } + } + compress_32b(c_board_p, flag_bit, board_block_num, BOARD_BIT); + compress_32b(c_board_p, flag_bit, board_block_type, BOARD_BIT); + + if (c_board_p - compress_board >= 200) { + compress_32b(p, flag_bit, 0, BOARD_BIT); + compress_bytes(p, flag_bit, non_compress_board, 200, BOARD_BIT); + } + else { + compress_32b(p, flag_bit, 1, BOARD_BIT); + compress_bytes(p, flag_bit, compress_board, c_board_p - compress_board, BOARD_BIT); + } + + compress_32b(p, flag_bit, pkt.type, TYPE_BIT); + compress_32b(p, flag_bit, pkt.rotation, ROTATION_BIT); + compress_32b(p, flag_bit, pkt.r, R_BIT); + compress_32b(p, flag_bit, pkt.c, C_BIT); + compress_32b(p, flag_bit, pkt.deleted_line, DELETED_LINE_BIT); - pkt.magic = read_32b(p); + if (pkt.is_game_over == 1) compress_32b(p, flag_bit, pkt.is_game_over, IS_GAME_OVER_BIT); + if (pkt.is_win == 1) compress_32b(p, flag_bit, pkt.is_win, IS_WIN_BIT); - for (int i = 0; i < 20; ++i) - for (int j = 0; j < 10; ++j) - pkt.board[i][j] = read_32b(p); + len = static_cast(strlen(pkt.id)); + compress_bytes(p, flag_bit, &len, 1, ID_BIT); + compress_bytes(p, flag_bit, pkt.id, len, ID_BIT); - pkt.type = read_32b(p); - pkt.rotation = read_32b(p); - pkt.r = read_32b(p); - pkt.c = read_32b(p); - pkt.deleted_line = read_32b(p); - pkt.is_game_over = read_32b(p); - pkt.is_win = read_32b(p); + // flag bit + write_32b(op, flag_bit); + + return (p - buf); +} + +bool WindowNetwork::deserialize(const uint8_t* buf, Packet& pkt) +{ + const uint8_t* p = buf; + uint32_t magic = 0; + uint32_t flag_bit = 0; + uint8_t len = 0; + uint32_t board_size = 200; + int32_t board_block_num = 0; + int32_t board_block_type = 0; + int32_t is_board_compressed = 0; + auto* board = &pkt.board[0][0]; + + magic = read_32b(p); + if (magic != PACKET_MAGIC) return false; + + flag_bit = read_32b(p); + + memset((void*) &pkt, 0, PACKET_SIZE); + + if (flag_bit & BOARD_BIT) { + decompress_32b(p, is_board_compressed); + + if (is_board_compressed == 1) { + while (board_size > 0) { + decompress_32b(p, board_block_num); + decompress_32b(p, board_block_type); + for (int i = 0; i < board_block_num; ++i) { + *(board++) = board_block_type; + } + board_size -= board_block_num; + } + } + else { + for (int i = 0; i < 20; ++i) + for (int j = 0; j < 10; ++j) + decompress_32b(p, pkt.board[i][j]); + } + } + if (flag_bit & TYPE_BIT) decompress_32b(p, pkt.type); + if (flag_bit & ROTATION_BIT) decompress_32b(p, pkt.rotation); + if (flag_bit & R_BIT) decompress_32b(p, pkt.r); + if (flag_bit & C_BIT) decompress_32b(p, pkt.c); + if (flag_bit & DELETED_LINE_BIT) decompress_32b(p, pkt.deleted_line); + if (flag_bit & IS_GAME_OVER_BIT) decompress_32b(p, pkt.is_game_over); + if (flag_bit & IS_WIN_BIT) decompress_32b(p, pkt.is_win); + if (flag_bit & ID_BIT) { + decompress_bytes(p, &len, 1); + decompress_bytes(p, pkt.id, len); + pkt.id[len] = '\0'; + } - read_bytes(p, pkt.id, 9); - pkt.id[8] = '\0'; + return true; } void WindowNetwork::send_udp(const Board& board, const Tetromino& tetromino, int deleted_line, int is_game_over, int is_win, @@ -130,19 +234,18 @@ void WindowNetwork::send_udp(const Board& board, const Tetromino& tetromino, int { Packet pkt{}; auto [pos_r, pos_c] = tetromino.get_pos(); - uint8_t buf[PACKET_SIZE]; + uint8_t buf[BUFFER_SIZE]; SOCKADDR_IN another_user; ZeroMemory(&another_user, sizeof(another_user)); another_user.sin_family = AF_INET; another_user.sin_port = htons(PORT); + uint32_t buffer_size = 0; // window에서는 inet_pton 사용 시 필요 inet_pton(AF_INET, another_user_ip, &another_user.sin_addr); // 보드 데이터 복사 - pkt.magic = PACKET_MAGIC; - for (int r = 0; r < 20; ++r) for (int c = 0; c < 10; ++c) pkt.board[r][c] = board.at(r + 2, c); // 숨겨진 2줄 제외하고 복사 @@ -154,11 +257,11 @@ void WindowNetwork::send_udp(const Board& board, const Tetromino& tetromino, int pkt.deleted_line = deleted_line; pkt.is_game_over = is_game_over; pkt.is_win = is_win; - snprintf(pkt.id, sizeof(pkt.id), "%s", my_id); + snprintf(pkt.id, PACKET_ID_SIZE, "%s", my_id); - serialize(buf, pkt); + buffer_size = serialize(buf, pkt); - int send_result = sendto(client_sock, (char*) buf, PACKET_SIZE, 0, (SOCKADDR*) &another_user, + int send_result = sendto(client_sock, (char*)buf, buffer_size, 0, (SOCKADDR*) &another_user, sizeof(another_user)); if (send_result == SOCKET_ERROR) { @@ -179,8 +282,10 @@ void WindowNetwork::send_relay_udp(const Packet& packet, std::vector> ids_ips) { char* another_user_ip; - uint8_t buf[PACKET_SIZE]; + uint8_t buf[BUFFER_SIZE]; SOCKADDR_IN another_user; + uint32_t buffer_size = 0; + int send_result = 0; for (const auto& [id, ip] : ids_ips) { if (strcmp(id.c_str(), packet.id) == 0) continue; @@ -193,9 +298,6 @@ void WindowNetwork::send_relay_udp(const Packet& packet, // window에서는 inet_pton 사용 시 필요 inet_pton(AF_INET, ip.c_str(), &another_user.sin_addr); - // 보드 데이터 복사 - pkt.magic = PACKET_MAGIC; - for (int r = 0; r < 20; ++r) for (int c = 0; c < 10; ++c) pkt.board[r][c] = packet.board[r][c]; // 숨겨진 2줄 제외하고 복사 @@ -207,12 +309,11 @@ void WindowNetwork::send_relay_udp(const Packet& packet, pkt.deleted_line = packet.deleted_line; pkt.is_game_over = packet.is_game_over; pkt.is_win = packet.is_win; - snprintf(pkt.id, sizeof(pkt.id), "%s", packet.id); + snprintf(pkt.id, PACKET_ID_SIZE, "%s", packet.id); - serialize(buf, pkt); + buffer_size = serialize(buf, pkt); - int send_result = sendto(client_sock, (char*) buf, PACKET_SIZE, 0, - (SOCKADDR*) &another_user, sizeof(another_user)); + send_result = sendto(client_sock, (char*)buf, buffer_size, 0, (SOCKADDR*) &another_user, sizeof(another_user)); if (send_result == SOCKET_ERROR) { cerr << "sendto failed: " << WSAGetLastError() << "\n"; @@ -222,37 +323,36 @@ void WindowNetwork::send_relay_udp(const Packet& packet, bool WindowNetwork::recv_udp(Packet& recv_pkt) { - uint8_t buf[PACKET_SIZE]; + uint8_t buf[BUFFER_SIZE]; bool data_received = false; SOCKADDR_IN client_addr; int addr_len = sizeof(client_addr); + bool is_deserialize_success = false; + int r; - // [window Non-blocking 처리] - // epoll 대신 루프를 돌며 쌓인 패킷을 모두 처리하고 가장 최신 것을 가져옵니다. - while (true) { - int r = - recvfrom(server_sock, (char*) buf, PACKET_SIZE, 0, (SOCKADDR*) &client_addr, &addr_len); - - if (r == SOCKET_ERROR) { - int err = WSAGetLastError(); - if (err == WSAEWOULDBLOCK) { - // 더 이상 읽을 데이터가 없음 (버퍼 비워짐) - break; - } - else { - // 진짜 에러 발생 + // [window Poll 처리] + int ret = WSAPoll(fds, 1, 0); + + if (ret > 0) { + if (fds[0].revents & POLLIN) { + r = recvfrom(server_sock, (char*) buf, BUFFER_SIZE, 0, (SOCKADDR*) &client_addr, + &addr_len); + + if (r == SOCKET_ERROR) { + int err = WSAGetLastError(); cerr << "recvfrom failed: " << err << "\n"; return false; } - } + else if (r < PACKET_MAGIC_SIZE) + return false; - // 데이터 수신 성공 - deserialize(buf, recv_pkt); + // 데이터 수신 성공 + is_deserialize_success = deserialize(buf, recv_pkt); - if (recv_pkt.magic != PACKET_MAGIC) - data_received = false; + if (is_deserialize_success == false) data_received = false; - data_received = true; + data_received = true; + } } return data_received; diff --git a/platform/window/source/render/window_multi_renderer.cpp b/platform/window/source/render/window_multi_renderer.cpp index 9957aa31..17df9e95 100644 --- a/platform/window/source/render/window_multi_renderer.cpp +++ b/platform/window/source/render/window_multi_renderer.cpp @@ -212,7 +212,7 @@ void WindowMultiRenderer::render_board(const Board& board, const Tetromino& tetr void WindowMultiRenderer::render_other_board(Packet& pkt) { auto [start_x, start_y] = other_render_loc_get_or_set(std::string(pkt.id)); - auto game_board = pkt.board; + auto& game_board = pkt.board; int pos_r = pkt.r; int pos_c = pkt.c; int mino_type = pkt.type;