49int main(
int argc,
char **argv) {
51 std::cerr <<
"Wrong number of arguments" << std::endl;
54 int port = std::atoi(argv[1]);
55 if (port <= 0 || port > 65535) {
56 std::cerr <<
"Wrong number of arguments" << std::endl;
60 std::signal(SIGPIPE, SIG_IGN);
62 MiniDb server(port, argv[2]);
96 std::cerr <<
"Fatal error" << std::endl;
115 : port_(port), path_(path), listen_fd_(-1), max_fd_(-1) {
130 for (std::map<int, std::string>::iterator it =
buffers_.begin();
161 if (setsockopt(
listen_fd_, SOL_SOCKET, SO_REUSEADDR, &opt,
sizeof(opt)) < 0)
165 std::memset(&addr, 0,
sizeof(addr));
166 addr.sin_family = AF_INET;
167 addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
168 addr.sin_port = htons(
static_cast<uint16_t
>(
port_));
170 if (bind(
listen_fd_,
reinterpret_cast<sockaddr *
>(&addr),
sizeof(addr)) < 0)
178 std::cout <<
"ready" << std::endl;
193 std::ifstream ifs(
path_.c_str());
196 std::string key, value;
197 while (ifs >> key >> value)
224 int rv = select(
max_fd_ + 1, &rfds, NULL, NULL, NULL);
230 for (
int fd = 0; fd <= max_fd_ && rv > 0; ++fd) {
231 if (!FD_ISSET(fd, &rfds))
290 ssize_t n = recv(fd, buf,
sizeof(buf), 0);
292 if (n < 0 && errno == EINTR)
298 acc.append(buf,
static_cast<size_t>(n));
299 std::string::size_type pos;
300 while ((pos = acc.find(
'\n')) != std::string::npos) {
301 std::string line = acc.substr(0, pos);
302 acc.erase(0, pos + 1);
304 send(fd, resp.c_str(), resp.size(), 0);
358 std::istringstream iss(line);
359 std::vector<std::string> tok;
366 if (tok[0] ==
"POST" && tok.size() == 3) {
367 db_[tok[1]] = tok[2];
370 if (tok[0] ==
"GET" && tok.size() == 2) {
371 std::map<std::string, std::string>::iterator it =
db_.find(tok[1]);
374 return "0 " + it->second +
"\n";
376 if (tok[0] ==
"DELETE" && tok.size() == 2) {
377 if (
db_.erase(tok[1]) == 0)
403 std::ofstream ofs(
path_.c_str());
406 for (std::map<std::string, std::string>::const_iterator it =
db_.begin();
407 it !=
db_.end(); ++it) {
408 ofs << it->first <<
" " << it->second <<
"\n";
int max_fd_
select に渡す最大 fd
fd_set active_fds_
現在監視中の fd 集合
int listen_fd_
リスニングソケット fd
std::string path_
永続化先ファイル (引数)
std::map< std::string, std::string > db_
Key-Value 本体
std::map< int, std::string > buffers_
fd → 未完成行バッファ
void accept_client()
accept(2) し、active_fds_ と buffers_ を更新する。
volatile sig_atomic_t g_running
サーバ実行継続フラグ (SIGINT で 0 になる)
int main(int argc, char **argv)
プログラムのエントリポイント
void load()
起動時に path_ を読み、空白区切り 1 行 1 ペアで db_ を初期化。
void fatal()
Fatal error\n を stderr に書いて exit(1) する
void recv_data(int fd)
recv(2) でデータを取り込み、行ごとに handle_command → send する。
void save() const
現在の DB をテキスト形式で永続化する
void run()
サーバのメインループ。SIGINT 受信で抜け、save() してから戻る。
void setup()
サーバ起動準備 (DB ロード → ソケット作成 → bind → listen → "ready")
MiniDb(int port, const std::string &path)
ポートと永続化先パスを束縛する
~MiniDb()
デストラクタ (全 fd をクローズ)
void disconnect(int fd)
fd を close し、active_fds_ / buffers_ から外し、max_fd_ を巻き戻す。
std::string handle_command(const std::string &line)
1行の入力に対して、応答文字列 (0\n / 0 <v>\n / 1\n / 2\n) を返す。
void on_sigint(int)
SIGINT ハンドラ。g_running を 0 にするだけ。