云端存储型编程向数据仓库
Chivas-Regal
作用
网络云空间很多,主体为支持普通用户的类似于云盘、云点播这类存放固定内容的平台
本工程可以用来搭建一个支持开发人员存放数据的网络远程空间
我们可以把 server 端搭在内存充足网络带宽速率快的服务器上,就可以按下面 client 演示在各个客户端使用这个服务器了
# code-api 使用演示
类似在 mem_socket_client 端写的:
// 一个自定义结构体
struct node {
int x, y;
node (int _x = 0, int _y = 0) :
x(_x),
y(_y) {}
};
Connector *conn = new Connector(); // 初始化一个 tcp 连接
conn->Login("test1", "test1"); // 登录 usr: test1, pwd: test1
conn->memAsk<node>("hello", 100); // 新建 node 数组 hello[100]
// 对每一个 hello[i] 赋值 {i, i + 1}
for (int i = 0; i < 10; i ++) {
conn->memWrite<node>("hello", node(i, i + 1), i);
std::cout << "client> SET hello[" << i << "] = {" << i << ", " << i + 1 << "}\n";
}
// 输出每一个 hello[i] 的值
for (int i = 0; i < 10; i ++) {
node rd = conn->memRead<node>("hello", i);
std::cout << "client> GET hello[" << i << "]\n";
std::cout << "server> {" << rd.x << ", " << rd.y << "}\n";
}
// 释放 node 数组 hello
conn->memFree("hello" + std::to_string(id));
// 关闭连接
conn->Exit();
exit(0);
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
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
当然运行之前必须要把 server 端打开运行
# local-cmd
这里就是我们本地运行时直接使用命令完成 KV 操作
这里我们写好的数值都可以在后面利用到来完成编程向数据库
注意这里数据的申请是不费我们自己的内存的
# 服务端
# 文件目录
├── CMakeLists.txt
├── README.md
├── backup
│ └── variable_info.txt
├── build
... 生成文件,不再放出来了
├── example
│ └── main.cpp
├── include
│ ├── channel.h
│ ├── config.h
│ ├── containers
│ │ └── trie.h
│ ├── epoll.h
│ ├── eventloop.h
│ ├── inet_address.h
│ ├── limits.h
│ ├── memtools
│ │ ├── memlist.h
│ │ ├── memlist_bf.h
│ │ ├── memlist_ff.h
│ │ ├── memlist_wf.h
│ │ ├── memlistnode.h
│ │ └── mempool.h
│ ├── server.h
│ ├── socket.h
│ ├── threads
│ │ └── threadpool.h
│ ├── usrinfo
│ │ └── sqlmanager.h
│ └── util.h
├── lib
│ ├── libmem_socket_server.dylib
│ ├── libmem_socket_server.so
│ └── libmysqlclient.so
├── src
│ ├── channel.cpp
│ ├── containers
│ │ └── trie.cpp
│ ├── epoll.cpp
│ ├── eventloop.cpp
│ ├── inet_address.cpp
│ ├── memtools
│ │ ├── memlist.cpp
│ │ ├── memlist_bf.cpp
│ │ ├── memlist_ff.cpp
│ │ ├── memlist_wf.cpp
│ │ ├── memlistnode.cpp
│ │ └── mempool.cpp
│ ├── server.cpp
│ ├── socket.cpp
│ ├── threads
│ │ └── threadpool.cpp
│ ├── usrinfo
│ │ └── sqlmanager.cpp
│ └── util.cpp
└── test
├── mempool.cpp
├── sqlmanager.cpp
└── thread.cpp
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
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
# 使用说明
网络与内存的配置信息和与客户端的交互都在 /include/config.h
中,其中默认
MEM_NUM_LISTS
内存池空闲链表数量MEM_SIZE_LIST
内存池一个空闲链表占用空间(单位:字节)MEM_POOL_ALGO
内存池内存分配所使用的算法FIRST_FIT
首次使用算法BEST_FIT
最佳适应算法WORST_FIT
最坏适应算法
SERVER_IP
服务端监听ip地址SERVER_PORT
服务端监听端口号SQL_IP
用户信息数据库连接的ip地址SQL_PORT
用户信息数据库连接的端口号SQL_USERNAME
用户信息数据库连接的用户名SQL_PASSWORD
用户信息数据库连接的密码SQL_DBNAME
用户信息选择存放数据库名
用户表在使用之前,应当在 mysql
对应的库内创建表:
CREATE TABLE IF NOT EXISTS mem_socket_login_infos (
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
PRIMARY KEY(username)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
1
2
3
4
5
2
3
4
5
程序不存在注册功能,可登入用户信息需数据库管理员手动录入
具体客户端如何与服务端进行联络请参考本仓库另一部分(客户端部分)
在客户端连接并登录上之后,通过指令向服务端提交变量操作
# 运行
本工程使用 cmake
,终端输入
cmake -B build
cd build
make
./memserverlib
1
2
3
4
2
3
4
# 功能 与 技术支持
- 以内存利用率为主的内存池设计(连续分区存储管理),支持
- 空闲节点的切割与合并
- 空闲链表动态插入节点
- 任意类型数据传输
- 数据拆分成多个字节发送
- 收取多个字节后按类型需要的字节数进行合并
socket
进程通信- 通过字符串通信模拟报头,完成前置指令
- 通过
uint8_t
传输完成字节信息传递(两个主机之间以大端字节序传输)
mysql
连接下的用户登入信息判断- 手写容器模板-字典树用于存放 “[用户名][变量名] - 值”
- 支持 string 与任意类型组成的键值对的存储
- 支持部分 map<string, 任意类型> 的操作
- 主动下的数据写入主存与读出
# 客户端接入
本服务端客户端通信均以 send/recv
方式交互
下面均是客户端应做的事情
通信内容
- 连接上
- 传入一个字符串代表登入用户的账号与密码
- 传入一个字符串包含操作字符与操作内容
- 操作字符
NEW
:表示新建空间,传入变量名与所需要的字节数GET
:表示读出数据,传入变量名与偏移首位置与偏移尾位置,会返回一个uint_8
类型的序列SET
:表示写入数据,传入变量名与偏移首位置与偏移尾位置,再传入一个uint_8
类型的序列DES
:表示释放空间,传入变量名- 其他:表示程序结束
连接 与 登录 与 所有非“其他”的操作,都会在结束后收到一个 "OK" 字符串
通信格式
对于所有的字符串类通信
先传入 '#'+单词个数n ,然后是 n 个 '$'+单词长度+' '+单词
每一部分后面都要带上 "\r\n"
CS对话示例如下:
== connect successfully ==
server> OK
client> #2\r\n
$3 zyz\r\n
$8 12345678\r\n
(解说:客户端登录,账号=zyz,密码=12345678)
server> OK
client> #3\r\n
$3 NEW\r\n
$3 var\r\n
$1 8\r\n
(解说:客户端新建变量,名为'var',8个字节,如本意为在客户端有 int* var = new int[2])
server> OK
client> #4\r\n
$3 SET\r\n
$3 var\r\n
$1 4\r\n
$1 7\r\n
client> 1,3,2,4
(解说:客户端设置 var[1] = 1*8+3*4+2*2+4 )
server> OK
client> #4\r\n
$3 GET\r\n
$3 var\r\n
$1 4\r\n
$1 7\r\n
(解说:客户端获取 var[1])
server> 1,3,2,4
server> OK
client> #2\r\n
$3 DES\r\n
$4 var\r\n
(解说:客户端释放变量 var,delete[] var)
server> OK
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
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
# 客户端
# 文件目录
├── CMakeLists.txt
├── README.md
├── build
... 生成文件,不再放出来了
├── example
│ └── memclientlib.cpp
├── include
│ ├── config.h
│ ├── connector.h
│ ├── inet_address.h
│ ├── limits.h
│ ├── socket.h
│ └── util.h
├── lib
│ └── libmem_socket_client.so
├── localwork.cpp
└── src
├── connector.cpp
├── inet_address.cpp
├── socket.cpp
└── util.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 使用说明
核心逻辑与服务端内的类似,这里只说明类 Connector
的使用方法
Connector
内部存在几个函数:
- 构造函数:构造的时候完成连接
- 登录函数
Login()
,参数为 (string)用户名 ,(string)密码 - 内存申请
memAsk()
,有一个模板参数表示申请的变量类型,函数参数 (string)变量名,(int)变量数量 - 变量赋值
memWrite()
,模板参数为对应变量类型,函数参数 (string)变量名,(变量类型)变量值,(int)变量位置(非数组0) - 变量获取
memRead()
,模板参数为对应变量类型,函数参数 (string)变量名,(int)变量位置(非数组0) - 内存释放
memFree()
,函数参数 (string)变量名 - 关闭连接
Exit()
配置信息在 "/include/config.h" 中,内部只有两个
- SERVER_IP
服务端 ip 地址
- SERVER_PORT
服务端端口号