ํ๊ตญ๊ณตํ๋ํ๊ต ์ ๋ดํ ๊ต์๋ 4-1 ๊ฒ์ ์๋ฒ ํ๋ก๊ทธ๋๋ฐ ์์ ์ค ์ผ๋ถ์ ๋๋ค.
- ๋คํธ์ํฌ ํ๋ก๊ทธ๋๋ฐ (์์ผ ํ๋ก๊ทธ๋๋ฐ)
: ํ๋ก์ธ์ค๋ค๋ผ๋ฆฌ ๋คํธ์ํฌ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ๋ ํ๋ก๊ทธ๋๋ฐ
: ํ์ผ I/O์ ๊ฑฐ์ ๋น์ทํ ์์ → Open, Close, Read, Write
: ๋คํธ์ํฌ I/O → Connect(Accept), Close(CloseSocket0, Recv, Send, ๋ฒํผ๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฃผ๊ณ ๋ฐ์ผ๋ฉฐ, ํ์ผ ์ด๋ฆ ๋์ Socket์ด๋ผ๋ ๋จ์ด ์ฌ์ฉ
: ์ฐจ์ด์ ์ → ํ์ผ ์ด๋ฆ ๋์ ๋คํธ์ํฌ ์ฃผ์ ์ฌ์ฉ, ์๋ฒ์ ๊ฒฝ์ฐ ์ด๋ ์ฃผ์์์ ์ฐ๊ฒฐ ์์ฒญ ์ฌ์ง ์ ์ ์๋ ๊ฒฝ์ฐ๊ฐ ๅค
: Recv ํธ์ถ ํ ๋ง์ด ๊ธฐ๋ค๋ฆฌ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ผ๋ฉฐ ๋ฒํผ๊ฐ ๋ค ์ฑ์์ง์ง ์๋ ๊ฒฝ์ฐ๊ฐ ๅค
- 4๊ณ์ธต
: ์ธํฐ๋ท์ 4๊ฐ์ ๋ ์ด์ด๋ก ๊ตฌํ
1) Application : ์ฐ๋ฆฌ๊ฐ ์์ฑํ๋ ํ๋ก๊ทธ๋จ,
2) Transport : Application์ ๋ฐ์ดํฐ๋ฅผ ์ ๋ฌํด์ฃผ๋ API → TCP/UDP
3) Network : ๋ฐ์ดํฐ๋ฅผ ๋ชฉ์ ์ง๊น์ง ์๋ดํ๋ ์์คํ → IPv4, IPv6
4) Data Link : ์ปดํจํฐ ์ฌ์ด๋ฅผ ์ฐ๊ฒฐํ๋ ๋ฌผ๋ฆฌ์ ๊ท๊ฒฉ → WiFi, Ethernet ...
- ํจํท(Packet)
: ์ธํฐ๋ท ํ์ค์์์ ํจํท → ๊ฐ ๋ ์ด์ด์์ ๋ค๋ฃจ๋ ๋ฐ์ดํฐ ๋จ์, ๊ฐ ๋ ์ด์ด์ ํ์ํ ์ ๋ณด๊ฐ ์ถ๊ฐ๋จ(ํค๋), ํจํท์ ๋ ๋ฆฝ์ .
: Application์์์ ํจํท → MMO ํจํท
: MMO ํจํท → ์ข ๋ฅ๊ฐ ๋ง์, ๋ค์ ํจํท ์์ธก ๋ถ๊ฐ, ํจํท๋ง๋ค์ ํฌ๊ธฐ ๋ค๋ฆ → ํจํท ์์ ์ ํจํท์ ์ข ๋ฅ์ ํฌ๊ธฐ ์์์ผ ํจ.
- ํ๋กํ ์ฝ
: ํ๋กํ ์ฝ → ํด๋ผ์ด์ธํธ์ ์๋ฒ ์ฌ์ด ๋ฐ์ดํฐ์ ํฌ๋งท๊ณผ ์์๋ฅผ ์ ์
: ์ ์ ๋ฐฉ์
1) Binary Format : Byte ๋จ์๋ก ๊ฐ ์๋ฏธ๋ฅผ ์ ์ → ๊ด๋ฆฌ ์ด๋ ค์ฐ๋ ์ธ์ด, OS, ์ปดํ์ผ๋ฌ์ ์ํฅ์ ๋ฐ์ง ์์
2) Structure Format : C์ ๊ตฌ์กฐ์ฒด ์ ์ํด์ ๊ณต์ →๊ด๋ฆฌ๊ฐ ์ฌ์ฐ๋, ์ธ์ด, OS, ์ปดํ์ผ๋ฌ์ ์ํฅ์ ๋ฐ์
3) SDK : ํ๋กํ ์ฝ ์ ์์ ํด์์ ๋์์ค
: ํจํท ์ฌ ์กฐ๋ฆฝ → ์ธํฐ๋ท ํ์ค์์์ ํจํท๊ณผ APP์์์ ํจํท์ด ๊ฐ์ง ์์, ์์ ์ชฝ์์ ์ด๋ป๊ฒ ํจํท์ ๋ฐ์๋์ง ์ ์ ์์ด์ ์ฌ ์กฐ๋ฆฝ์ด ํ์ํจ
- ์์ผ ํ๋ก๊ทธ๋๋ฐ
: ํ์ผ I/O์ ๋น์ท
: Client → Socket - Connect - Recv/Send - Close
: Server → Socket - Bind - listen - Accept - Recv/Send - Close
// Client
SOCKET s = socket(AF_INET, SOCK_STREAM, 0); // socket
sockaddr addr;
addr.sin_addr.s_addr = ...;
addr.sin_port = PORT;
connect(s, &addr, ...) // connect
...
sent = send(s, buf, size, flags); // send
r_size = recv(s, buf, max_size, flags); // recv
...
closesocket(s); // closesocket
// Server
SOCKET s = socket(AF_INET, SOCK_STREAM, 0); // socket
sockaddr c_addr;
c_addr.sin_port = PORT;
bind(s, &c_addr); // bind
listen(s, 3); // listen
sockaddr n_addr;
SOCKET c = accept (s, &n_addr); // accept
...
r_size = recv(c, buf, max_size, flags); // recv
sent = send(c, buf, size, &sent, flags); // send
...
closesocket(c); // closesocket
- Windows Socket API
: ๊ณ ์ฑ๋ฅ ๋คํธ์ํฌ I/O๋ฅผ ์ํด์๋ ์ ์ฉ API ํ์ → WSASocket(), WSAConnect(), WSAAccept(), WSASend(), WSARecv()
// SOCKADDR ์ฃผ์ ๊ตฌ์กฐ์ฒด
// ๋คํธ์ํฌ ์ฃผ์๋ฅผ ์ ์ฅ
// IP์ฃผ์ + PORT ๋ฒํธ(IP ์ฃผ์ใ
-> ์ปดํจํฐ, PORT ๋ฒํธ -> ํ๋ก์ธ์ค)
// ์ ์ธ
struct sockaddr addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(SERVER_PORT);
inet_pton(AF_INET, SERVER_IP, &addr.sin_addr);
// SEVER_PORT๋ short, SERVER_IP๋ ๋ฌธ์์ด
//////////////////////////////////////////////////////////
// WSABUF(gather/scatter I/O) :ํฉ์ด์ง ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ ๊ตฌ์กฐ
// − ๋ฐ์ดํฐ ๋ณต์ฌ(์ฑ๋ฅ ์ ํ ์ฃผ๋ฒ) ๊ฐ์
typedef struct __WSABUF
{
u_long len;
char FAR *buf;
} WSABUF, *LPWSAVUF;
// WSABUF๋ฅผ ์ฌ์ฉํ ์ต์ ํ
// Move_p, Attack_p, Chat_p -> 3๊ฐ์ ํจํท์ ๋ณด๋ด์ผ ํ๋ค
// 1. ๊ธฐ์กด ๋ด๊ฐ ์๋ ๋ฐฉ์
// ์ฌ๋ฌ ๋ฒ์ ์์คํ
ํธ์ถ์ด ํ์ํ๋ฏ๋ก ์ค๋ฒํค๋ ๋ฐ์
Send(s, &move_p. sizeof(move_p));
Send(s, &attack_p. sizeof(attack_p));
Send(s, &chat_p. sizeof(chat_p));
// 2
// ๋ฉ๋ชจ๋ฆฌ ์ถ๊ฐ์ฌ์ฉ ๋ฐ ๋ฉ๋ชจ๋ฆฌ ๋ณต์ -> ์ค๋ฒํค๋
Char buf[1024]; int pos = 0;
Memcpy(buf, &move_p, sizeof(move_p)); pos+=sizeof(move_p);
Memcpy(buf + pos, &attack_p, sizeof(attack_p)); pos+=sizeof(attack_p);
Memcpy(buf + pos, &chat_p, sizeof(chat_p)); pos+=sizeof (chat_p);
Send(s, buf, pos);
// 3
WSABUF buf[3];
Buf[0].buf = &move_p; buf[0].len = sizeof(move_p);
Buf[0].buf = &attack_p; buf[0].len = sizeof(attack_p);
Buf[0].buf = &chat_p; buf[0].len = sizeof(chat_p);
WSASend(s, buf, 3);
#include <iostream>
#include <WS2tcpip.h> // header
// 1. Socket ๋ง๋ค๊ธฐ
SOCKET WSASocket(int af, int type, int protocol,
LPWSAPROTOCOL_INFO lpProtocolInfo, GROUP g, DWORO dwFlags)
// af : address family -> AF_INET ์ฌ์ฉ
// type : socket type -> SOCK_STREAM(TCP)
// protocol : ์ฌ์ฉํ ํ๋กํ ์ฝ ์ข
๋ฅ (IPPROTO_TCP/IPPROTO_UDP)
// lpProtocolInfo : protocol infomation (NULL)
// g : ์์ฝ
// dwFlags : ์์ผ ์์ฑ (๋ณดํต 0 or WSA_PROTOCOL_OVERLAPPED)
// 2. Socket ์ฐ๊ฒฐ
// ๋๊ธฐํ๊ณ ์๋ ์๋ ์์ผ์ ์์ ์ ์์ผ ์ฐ๊ฒฐ
int WSAConnect(SOCKET s, const struct sockaddr* name,
int namelen, LPWSABUF lpCallerData, LPWSABUF lpCalleeData,
LPQOS lpSQOS, LPQOS lpGQOS)
// s : ์์ผ
// name, namelen : ์๋ ์์ผ ์ฃผ์์ ์ฃผ์ ๊ธธ์ด -> ๋ณดํต sockaddr_in ๊ตฌ์กฐ์ฒด ์ฌ์ฉ
// lpCallerData : ์ฐ๊ฒฐ ์์ฒญ ์์ ์ ์กํ ๋ฐ์ดํฐ์ ๋ฒํผ๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ -> ๋ณดํต sizeof(struct sockaddr)
// lpCalleeData : ์ฐ๊ฒฐ ์์ฒญ์ ๋ํ ์๋ต์ผ๋ก ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ฒํผ๋ฅผ ๊ฐ๋ฆฌํค๋ ํฌ์ธํฐ
// lpSQOS, lpGQOS : ํ์ง ์๋น์ค(Quality of Service, QoS) ์๊ตฌ ์ฌํญ ์ง์ ํฌ์ธํฐ
// 3. Socket์์ ๋ฐ์ดํฐ ๋ฐ๊ธฐ
int WSARecv(SOCKET s, LPWSABUF lpBuffers, DWORD dwBufferCount,
LPDWORD lpNumberofBytesRecvd, LPDWORD lpFlags,
LPWSAOVERLAPPED lpOverlapped, LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine)
// s : ์์ผ
// lpBuffers : ๋ฐ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ๋ฒํผ
// dwBufferCount : ๋ฒํผ ๊ฐ์
// lpFlags : ๋์ ์ต์
(MSG_PEEK, MSG_OOB)
// - MSG_PEEK : ๋ฐ์ดํฐ๋ฅผ ์์ ํ ๋, ๋ฒํผ์์ ๋ฐ์ดํฐ๋ฅผ ์ ๊ฑฐํ์ง ์๊ณ ๋ฐ์ดํฐ๋ฅผ ํ์ธ ๊ฐ๋ฅ, ๋ฐ์ดํฐ๊ฐ ๋ฒํผ์์ ์ ๊ฑฐX
// - MSG_OOB : ๊ธด๊ธ(out-of-band) ๋ฐ์ดํฐ๋ฅผ ์์ผ์ผ๋ก๋ถํฐ ์ฝ๊ฑฐ๋ ์ ์ก
// lpNumberofBytesRecvd : ๋ฐ์ ๋ฐ์ดํฐ ํฌ๊ธฐ
// lpOverlapped, lpCompletionRoutine : ๋ค์ ์ค๋ช
// 4. Socket ๋๊ธฐ
int closesocket(SOCKET s)
// s : ์์ผ
// return value : 0 (success)
// 5. PORT ๋ฌถ๊ธฐ
// ํฌํธ๋ฅผ ์ ์ ํด ๋ค๋ฅธ ํ๋ก๊ทธ๋จ์ด ์ฌ์ฉํ์ง ๋ชปํ๋๋ก ํจ
int bind(SOCKET s, const struct sockaddr* name, int namelen)
// s : ์์ผ
// name, namelen : ์๋ ์์ผ ์ฃผ์์ ์ฃผ์ ๊ธธ์ด
// - INADDR_ANY : ์ ์ฒด ์ฃผ์๋ก๋ถํฐ ์ ์ ํ์ฉ
// - info.sin_affr.S_in.S_addr = htonl(INADDR_ANY)
// - htonl : ํธ์คํธ ๋ฐ์ดํธ ์์๋ฅผ ๋คํธ์ํฌ ๋ฐ์ดํธ ์์๋ก ๋ณํ
// 6. Socket ์ ์ ๋๊ธฐ
// ์์ผ ์ ์์ ๋ฐ์ ์ ์๋ ์ํ
int listen(SOCKET s, int backlog)
// s : ์์ผ
// backlog : ์ ์ ๋๊ธฐ ํ์ ์ต๋ ์ฐ๊ฒฐ ๊ฐ๋ฅ ์ซ์
// - ์๋ฒ์ ๋์ฐฉ ํ accept๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ณ ์๋ ์์ผ ์ฐ๊ฒฐ์ ์ต๋ ์
// - ์ฑ๊ธ ์ค๋ ๋ ํ๋ก๊ทธ๋จ์์๋ 5์ ๋๊ฐ ์ ๋น, ๋์ฉ๋ ์๋ฒ๋ 20-200 or SOMAXCONN
// 7. ์ฐ๊ฒฐ Socket ์์ฑ
// ์ฐ๊ฒฐ๋ ์์ผ์ ๋ง๋ฆ
SOCKET WSAAccept(SOCKET s, struct sockaddr* name, LPINT addrlen,
LPCONDITIONPROC lpfnCondition, DWORD dwCallbackData)
// s : listen์ ํ๊ณ ์๋ ์์ผ
// name, addrlen : ์ฐ๊ฒฐ๋ ์๋ ์์ผ ์ฃผ์
// lpfnCondition : ์ฐ๊ฒฐ ๊ฑฐ์ ์ ํ๋จํ๋ ํจ์ (NULL)
// dwCallbackData : lpfnCondition์ ๋ค์ด๊ฐ ๊ฐ
// Return value : ๋ฐ์ดํฐ ์ ์ก์ฉ ์์ผ
// ๋๋ฒ๊น
tip
void error_display(const char *msg, int err_no )
{
WCHAR *lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err_no,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpMsgBuf, 0, NULL );
std::cout << msg;
std::wcout << L" ์๋ฌ " << lpMsgBuf << std::endl;
while(true); // ๋๋ฒ๊น
LocalFree(lpMsgBuf);
}
// + ํ๊ธ
std::wcout.imbue(std::locale("korean"));
- ๊ฐ๋จํ ์ค์ต (Echo 1๋1)
// Client
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "WS2_32.LIB")
constexpr short PORT = 4000;
constexpr char SERVER_ADDR[] = "127.0.0.1";
constexpr int BUFSIZE = 256;
int main()
{
std::wcout.imbue(std::locale("korean"));
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 2), &WSAData);
SOCKET server_s = WSASocket(AF_INET, SOCK_STREAM,
IPPROTO_TCP, nullptr, 0, 0);
SOCKADDR_IN server_a;
server_a.sin_family = AF_INET;
server_a.sin_port = htons(PORT);
inet_pton(AF_INET, SERVER_ADDR, &server_a.sin_addr);
connect(server_s, reinterpret_cast<sockaddr*>(&server_a), sizeof(server_a));
// reinterpret_cast<type_id>(expression);
// type_id: ๋ฐ๊ฟ ํ์
/ expression : ๋์
// ํฌ์ธํฐ -> ํฌ์ธํฐ, ํฌ์ธํฐ -> ์ผ๋ฐ ๋ณ์, ์ผ๋ฐ ๋ณ์ -> ํฌ์ธํฐ, ์๋ฃํ -> ๋ค๋ฅธ ์๋ฃํ
// connect ํจ์๋ sockaddr ๊ตฌ์กฐ์ฒด๋ฅผ ์๊ตฌํ๋ฏ๋ก,
// reinterpret_cast๋ฅผ ์ฌ์ฉํ์ฌ server_a๋ฅผ sockaddr* ํ์
์ผ๋ก ๋ณํ
while (true) {
char buf[BUFSIZE];
std::cout << "Enter Message : ";
std::cin.getline(buf, BUFSIZE); // enter๊ธฐ์ค getline
WSABUF wsabuf[1];
wsabuf[0].buf = buf;
wsabuf[0].len = static_cast<int>(strlen(buf)) + 1;
if (wsabuf[0].len == 0)
break;
DWORD sent_size;
WSASend(server_s, wsabuf, 1, &sent_size, 0, nullptr, nullptr);
wsabuf[0].len = BUFSIZE; // ์ผ๋ง๋ ์ฌ์ง ๋ชจ๋ฅด๋ ์ต๋ ์ฌ์ด์ฆ
DWORD recv_size;
DWORD recv_flag = 0; // ์ด๊ธฐํ ํ์
WSARecv(server_s, wsabuf, 1, &recv_size, &recv_flag, nullptr, nullptr);
for (DWORD i = 0; i < recv_size; ++i)
std::cout << buf[i];
std::cout << std::endl;
}
closesocket(server_s);
WSACleanup();
}
// Server
#include <iostream>
#include <WS2tcpip.h>
#pragma comment (lib, "WS2_32.LIB")
constexpr short PORT = 4000;
constexpr int BUFSIZE = 256;
void print_error(const char* msg, int err_no)
{
// ์ถ๋ ฅ ๋ฉ์ธ์ง๋ฅผ ์ ์ฅํ buf
WCHAR* msg_buf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL, err_no, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), reinterpret_cast<LPWSTR>(&msg_buf), 0, NULL);
std::cout << msg;
std::wcout << L" : ์๋ฌ : " << msg_buf;
while (true); // ๋๋ฒ๊น
LocalFree(msg_buf);
}
int main()
{
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 2), &WSAData);
SOCKET server_s = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, nullptr, 0, 0);
SOCKADDR_IN server_a;
server_a.sin_family = AF_INET;
server_a.sin_port = htons(PORT);
server_a.sin_addr.S_un.S_addr = htons(INADDR_ANY);
bind(server_s, reinterpret_cast<sockaddr*>(&server_a), sizeof(server_a));
listen(server_s, SOMAXCONN);
int addr_size = sizeof(server_a);
SOCKET client_s = WSAAccept(server_s, reinterpret_cast<sockaddr*>(&server_a), &addr_size, nullptr, 0);
std::cout << "์ฑ๊ณต : " << server_a.sin_port << std::endl;
while (true) {
char buf[BUFSIZE];
WSABUF wsabuf[1];
wsabuf[0].buf = buf;
wsabuf[0].len = BUFSIZE; // ์๋ฒ๋ก๋ถํฐ ์ผ๋ง ์ฌ์ง ๋ชจ๋ฅด๋ ์ต๋ ์ฌ์ด์ฆ
DWORD recv_size;
DWORD recv_flag = 0; //์ด๊ธฐํ ์ํ๋ฉด ์ด์ํ๊ฒ ๋ฐ์ผ๋ ค ํจ
int res = WSARecv(client_s, wsabuf, 1, &recv_size, &recv_flag, nullptr, nullptr);
if (res != 0) {
print_error("WSARecv", WSAGetLastError());
}
if (recv_size == 1)
break;
std::cout << "Client Sent : ";
for (DWORD i = 0; i < recv_size; ++i)
std::cout << buf[i];
std::cout << std::endl;
wsabuf[0].len = recv_size;
DWORD sent_size;
WSASend(client_s, wsabuf, 1, &sent_size, 0, nullptr, nullptr);
}
closesocket(server_s);
closesocket(client_s);
WSACleanup();
}
'๐ค Study > Game Server' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[06์ฃผ์ฐจ] ๋ฉํฐ์ฐ๋ ๋ 01 (0) | 2024.04.22 |
---|---|
[05์ฃผ์ฐจ] IOCP (0) | 2024.04.22 |
[04์ฃผ์ฐจ] I/O ๋ชจ๋ธ (0) | 2024.04.22 |
[02์ฃผ์ฐจ] ํ๊ฒฝ (1) | 2024.04.19 |
[01์ฃผ์ฐจA] ๊ฒ์ ์๋ฒ (1) | 2024.03.12 |