일단 redis 설치부터 시작해서, cpp_redis 라이브러리 빌드 그리고
tcp_client와 tcp_server를 활용해 async_write, async_read 까지 테스트해본다.
언제나 그렇듯 부족하거나 틀린 부분이 있으면 지적해주시면 확인해보고 수정하겠습니다 :)
테스트 환경은 윈도우10 64비트이다.
우선 설치부터 시작해보자.
1. 아래 링크에서 .msi 파일을 다운로드하여 설치한다.
https://github.com/MicrosoftArchive/redis/releases
2. 아래 링크는 redis manager인데, 지금하고자 하는 것에는 사용하지 않는다.
다만, 1번 링크 설치 후에 간단한 key/value 값 넣고 확인해본다거나 하실려면 설치!
https://sourceforge.net/projects/redis-desktop-manager.mirror/
3. redis를 사용할 수 있는 것들 중 나는 cpp_redis를 선택했다.
아래 링크에서 체크아웃하였다. 우리는 visual studio를 통해 빌드할 예정이다.
https://github.com/Cylix/cpp_redis
4. 3번에서 체크 아웃 받은 프로젝트의 폴더로 가보면 아래 경로에 tacopie.sln 이 있다.
..\cpp_redis\msvc15
5. 만약 현재 환경이 visual studio 2017이고, Windows SDK 버전도 상위라면
프로젝트 속성에서 변경해줘야 한다.
6. 빌드를 완료하면, 아래 경로에 tacopie.lib 파일이 있을 것이다.
\cpp_redis\msvc15\x64\Debug 또는 Release
7. 이제 테스트를 위한 윈도우 콘솔 솔루션을 생성하고
TestRedisClient, TestRedisServer 와 같이 2개의 프로젝트를 생성한다.
프로젝트명은 각자 원하시는대로 하시면 된다.
8. 두 프로젝트 모두 다 tacopie.lib를 사용하기 위한 설정을 해준다.
나는 아래와 같이 4개의 항목을 수정했다.
디렉터리는 아래와 같이 2개를 추가 했다.
\cpp_redis\includes
\cpp_redis\includes\tacopie
- 이 폴더 안에 tacopie.lib 파일을 넣어두었다.
구성속성 > VC++ 디렉터리 > 포함 디렉터리
구성속성 > VC++ 디렉터리 > 라이브러리 디렉터리
구성속성 > C/C++ > 추가 포함 디렉터리
구성속성 > 링커 > 입력 > 추가 종속성 (tacopie.lib 추가)
자.. 그러면 프로젝트 준비는 어느 정도 된 것 같고 아래에는 내가 테스트한 소스다.
github에 보면 example 코드가 있는데 그거와 거의 동일하다.
몇 가지 내가 주석을 달고, client 측에서 async_write를 사용한 것 빼고..
<TestRedisClient>
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
#include "pch.h"
#include <iostream>
#include <WinSock2.h>
#include <tacopie/tacopie>
#include <condition_variable>
#include <mutex>
#include <signal.h>
using namespace std;
std::condition_variable cv;
void signint_handler(int)
{
// 주의:
// 스레드는 아래 두 메서드에 의해 깨어날 수도 있지만,
// 타임 아웃으로 인해 깨어날 수도 있다.
// 이 조건 변수를 기다리고 있는 스레드 중 한 개의 스레드를 깨운다.
//cv.notify_one();
// 이 조건 변수를 기다리고 있는 모든 스레드를 깨운다.
cv.notify_all();
}
void on_new_message(tacopie::tcp_client& client, const tacopie::tcp_client::read_result& res)
{
if (res.success)
{
std::cout << "Client recv data" << std::endl;
client.async_write({ res.buffer, nullptr });
client.async_read({ 1024, std::bind(&on_new_message, std::ref(client), std::placeholders::_1) });
}
else
{
std::cout << "Client disconnected" << std::endl;
client.disconnect();
}
}
int main()
{
WORD version = MAKEWORD(2, 2);
WSADATA data;
// 이 과정을 해주지 않으면 cpp_redis 정상적으로 동작하지 않는다.
// 이 녀석도 소켓을 쓰는 거니까
if (0 != WSAStartup(version, &data))
{
cout << "WSAStartup fail" << "\n";
return -1;
}
tacopie::tcp_client client;
client.connect("127.0.0.1", 3000);
client.async_read({ 1024, std::bind(&on_new_message, std::ref(client), std::placeholders::_1) });
vector<int> v = { 1, 2, 3, 4, 5 };
tacopie::tcp_client::write_request a;
a.buffer.push_back(1);
a.buffer.push_back(2);
a.buffer.push_back(3);
a.buffer.push_back(4);
a.buffer.push_back(5);
client.async_write({ a.buffer, nullptr });
// SIGINT 값은 사용자가 Ctrl+C키를 입력했을 때 들어온다.
// 즉, signint_handler함수를 호출해 notify 해줌으로써
// 아래에서 lock(mtx)에 잠긴 스레드를 깨운다.
signal(SIGINT, &signint_handler);
std::mutex mtx;
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
WSACleanup();
system("pause");
return 0;
}
| cs |
<TestRedisServer>
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
|
#include "pch.h"
#include <tacopie/tacopie>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <signal.h>
#include <Winsock2.h>
std::condition_variable cv;
void signint_handler(int)
{
cv.notify_all();
}
void on_new_message(const std::shared_ptr<tacopie::tcp_client>& client, const tacopie::tcp_client::read_result& res)
{
if (res.success)
{
std::cout << "Client recv data" << std::endl;
client->async_write({ res.buffer, nullptr });
client->async_read({ 1024, std::bind(&on_new_message, client, std::placeholders::_1) });
}
else
{
std::cout << "Client disconnected" << std::endl;
client->disconnect();
}
}
int main(void)
{
//! Windows netword DLL init
WORD version = MAKEWORD(2, 2);
WSADATA data;
if (WSAStartup(version, &data) != 0)
{
std::cerr << "WSAStartup() failure" << std::endl;
return -1;
}
tacopie::tcp_server s;
s.start("127.0.0.1", 3000, [](const std::shared_ptr<tacopie::tcp_client>& client) -> bool
{
std::cout << "New client" << std::endl;
client->async_read({ 1024, std::bind(&on_new_message, client, std::placeholders::_1) });
return true;
});
signal(SIGINT, &signint_handler);
std::mutex mtx;
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock);
WSACleanup();
system("pause");
return 0;
}
| cs |
댓글 없음:
댓글 쓰기