일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 |
- placement new
- virtual inheritance
- std::ostream
- diamond inheritance
- base from member
- vector capacity
- std::endl
- discord bot
- virtual function
- member function pointer
- vector size
- new&delete
- std::vector
- C++
- this call
- c++ basic practice
- virtual destructor
- conversion constructor
- virtual function table
- return by reference
- delete function
- c++ multi chatting room
- 더 지니어스 양면포커
- constructor
- operator overloading
- dynamic_cast
- increment operator
- std::cout
- pointer to member data
- suffix return type
- Today
- Total
I'm FanJae.
[C++ Server] Day 1. Echo Server 구현. 본문
[C++ Server] Day 1. Echo Server 구현.
FanJae 2024. 9. 25. 16:231. 윈도우 소켓 프로그래밍 서버 설정
- 윈도우 소켓(윈속)도 기본적으로 BSD 계열 유닉스 소켓과 유사한 부분을 많이 띄고 있다.
1-1. 윈도우 소켓 프로그래밍 서버의 설정 순서
① 윈속(Winsock) 초기화 -> WSAStartup() 호출.
② 소켓 생성 -> socket() 호출
③ 소켓 주소 구조체 설정 -> sockaddr_in 구조체
④ 소켓에 ip주소 및 포트 정보 할당 -> bind() 호출
⑤ 연결 대기 상태 -> listen() 호출
⑥ 연결 요청 수락 -> accept() 호출
⑦ 소켓 종료 및 윈속 해제-> closesocket(), WSACleanup()
- 위 순서대로 서버를 구성한다.
※ sockaddr_in 구조체 관련 정보
typedef struct sockaddr_in {
#if ...
short sin_family;
#else
ADDRESS_FAMILY sin_family;
#endif
USHORT sin_port;
IN_ADDR sin_addr;
CHAR sin_zero[8];
} SOCKADDR_IN, *PSOCKADDR_IN;
- 링크 : https://learn.microsoft.com/en-us/windows/win32/api/ws2def/ns-ws2def-sockaddr_in
sin_family : 주소 체계를 의미. 이 멤버는 AF_INET으로 설정함.
sin_port : 전송 프로토콜의 포트 번호
sin_addr : IPv4 전송 주소를 포함하는 IN_ADDR 구조체
sin_zero[8] : 시스템 사용을 위해 예약.
1-2. 기본적인 서버 구현
① 윈속 초기화 -> WSAStartup() 호출.
#include <iostream>
#include <WinSock2.h>
int main(int argc, char *argv[])
{
char message[] = "Message";
WSADATA wsaData;
SOCKET serverSocket;
SOCKADDR_IN serverAddr;
if (argc != 2) // Port 번호를 직접 작성하는 방식으로 사용하기 위함으로 필수는 아님.
{
std::cerr << "Usage : <port> : " << argv[0];
return 1;
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cerr << "WSAStartup() Error" << std::endl;
return 1;
}
}
② 소켓 생성 -> socket() 호출
serverSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (serverSocket == INVALID_SOCKET)
{
std::cerr << "Socket() Error" << std::endl;
return 1;
}
③ 서버 주소 설정 -> sockaddr_in 구조체 설정
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = INADDR_ANY;
serverAddr.sin_port = atoi(argv[1]);
④ 소켓에 ip주소 및 포트 정보 할당 -> bind() 호출
if (bind(serverSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
std::cerr << "bind() Error" << std::endl;
return 1;
}
⑤ 연결 대기 상태 -> listen() 호출
if (listen(serverSocket, SOMAXCONN) == SOCKET_ERROR)
{
std::cerr << "listen() Error" << std::endl;
return 1;
}
- 서버 소켓을 수신 상태로 만들어준다. 문제는 여기서 2번째 인자인 backlog에 들어갈 값이 애매해서 찾아보았다.
- Backlog가 무엇일까 확인해 볼 때 다음과 같이 적혀있다.
The maximum length of the queue of pending connections. If set to SOMAXCONN, the underlying service provider responsible for socket s will set the backlog to a maximum reasonable value.
- 즉, 연결을 대기중인 클라이언트의 요청을 큐에 보관할 수 있는 최대 개수를 지정하는 것이다.
- SOMAXCONN으로 소켓 s에 대해서 서비스 공급자가 합리적인 값으로 설정한다고 한다.
⑦ 연결 요청 수락 - > accept() 호출
SOCKET clientSocket;
sockaddr_in clientAddr;
int clientAddrSize = sizeof(clientAddr);
clientSocket = accept(serverSocket, (sockaddr*)&clientAddr, &clientAddrSize);
if (clientSocket == INVALID_SOCKET)
{
std::cerr << "accept() Error" << std::endl;
return 1;
}
send(clientSocket, message, sizeof(message), 0);
- 실질적으로 Multi Thread 환경을 전제하여 만들고 있기 때문에 이곳에서 Thread 처리를 진행해야 한다.
⑧ 소켓 종료 및 윈속 해제-> closesocket(), WSACleanup()
closesocket(clientSocket);
closesocket(serverSocket);
WSACleanup();
- 서버 소켓을 종료 해주고, 소켓 라이브러리를 해제하는 것으로 마무리 된다.
2. 테스트용 클라이언트 작성 (C++ CUI)
- 기본적인 서버기 때문에 테스트 클라이언트로 해당 서버가 정상 작동하는지만 확인한다.
- 이를 먼저 하는 이유는 소켓 통신 자체에 이상이 없는지 먼저 확인하기 위함이다.
2-1. 윈도우 소켓 프로그래밍 서버의 설정 순서
① 윈속(Winsock) 초기화 -> WSAStartup() 호출.
② 소켓 생성 -> socket() 호출
③ 소켓 주소 구조체 설정 -> sockaddr_in 구조체
④ 연결 요청 -> connect() 호출
⑤ 소켓 종료 및 윈속 해제-> closesocket(), WSACleanup()
※ 서버에 비하면, 클라이언트 쪽은 연결 과정이 훨씬 더 간단하다.
2-2. 기본적인 서버 구현
① 윈속 초기화 -> WSAStartup() 호출.
#include <iostream>
#include <Winsock2.h>
int main(int argc, char* argv[])
{
char buffer[1024];
WSAData wsaData;
SOCKET clientSocket;
sockaddr_in serverAddr;
if (argc != 3)
{
std::cerr << "Usage : " << argv[0] << " <IP> <port>";
return 1;
}
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
std::cerr << "WSAStartup() Error";
return 1;
}
}
② 소켓 생성 -> socket() 호출
clientSocket = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
if (clientSocket == INVALID_SOCKET)
{
std::cerr << "socket() Error";
return 1;
}
③ 소켓 주소 구조체 설정 -> sockaddr_in 구조체
serverAddr.sin_family = AF_INET;
serverAddr.sin_addr.s_addr = inet_addr(argv[1]);
serverAddr.sin_port = atoi(argv[2]);
④ 연결 요청 -> connect() 호출
if (connect(clientSocket, (SOCKADDR*)&serverAddr, sizeof(serverAddr)) == SOCKET_ERROR)
{
std::cerr << "connect() Error";
return 1;
}
⑤ 소켓 종료 및 윈속 해제-> closesocket(), WSACleanup()
closesocket(clientSocket);
WSACleanup();
3. 테스트
- Server와 Client간 메시지를 정상적으로 주고 받는 것을 확인할 수 있다.
- 이제 Thread를 이용해서 이를 어떻게 Multi-Room Chatting Server를 구현할지 구성할 것이다.
4. TODO
1) Server
- Multi Thread를 이용한 Multi-Room 구현
2) Client
- 기능 테스트를 위한 CUI 환경 필요
- C# Windows Forms을 이용한 GUI 구현 필요
'Toy Project > Multi Room Cheating Server' 카테고리의 다른 글
[C++ Server, C# Client] Day 3. GUI 클라이언트 설계 및 Server 버그 수정 (0) | 2024.09.26 |
---|---|
[C++ Server] Day 2. Thread 적용 및 Multi Chatting Room 구현 (2) | 2024.09.25 |
[C++ Server, C# Client] Day 0. Multi Room Chatting Server 시작 (3) | 2024.09.24 |