가상SSD프로그램

아무개·2024년 9월 23일

C/C++

목록 보기
6/6

전체적인 구상도
user가 shell.exe를 이용해 ssd.exe를 제어한다.

ssd.exe
write하면 nand.txt에 값 저장 read하면 result.txt에 읽은 값 저장
shell.exe
write: ssd에 명령어 전달
read: ssd에 명령어 전달 + result 출력
fullwrite: LBA 0번부터 99번까지 write 수행
fullread: LBA 0번부터 99번까지 read 수행

유효성검사
LBA의 범위는 0 ~ 99
값은 16진수로 A ~ F, 0 ~ 9까지 숫자범위 허용
없는 명령어 수행 시 "INVALID COMMAND" 출력

ssd.cpp

#include "storage.h"
#include <fstream>
#include <string.h>

class SSD: public Storage{
private:
    std::string buf[100]; // LBA는 4Byte 크기
    std::string line;
public:
    void write(uint32_t address, std::string value){
        std::ofstream fout("nand.txt", std::ios::app);
        fout << address << '-' << value << '\n';
        fout.close();
    }

    void read(uint32_t address, bool flag){
        std::ifstream fin("nand.txt");
        while (std::getline(fin, line)) {
            if(line[1] == '-'){
                buf[stoi(line.substr(0, 1))] = line.substr(2); 
            }
            else if(line[2] == '-'){
                buf[stoi(line.substr(0, 2))] = line.substr(3); 
            }
        }
        fin.close();

        if(flag){
            std::ofstream fout("result.txt", std::ios::app);
            fout << buf[address] << '\n';
            fout.close();
        }
        else{
            std::ofstream fout("result.txt");
            fout << buf[address] << '\n';
            fout.close();
        }
    }

    SSD(){
        std::fill_n(buf, 100, "00000000");
    }
};


int main(int argc, char* argv[]){ // argv[0]은 파일명
    SSD ssd;
    if(strcmp(argv[1], "W") == 0){
        ssd.write(atoi(argv[2]), argv[3]);
    }
    else if(strcmp(argv[1], "R") == 0){
        if(strcmp(argv[3], "FULL") == 0) {
            ssd.read(atoi(argv[2]), 1);
        }
        if(strcmp(argv[3], "ONE") == 0) {
            ssd.read(atoi(argv[2]), 0);
        }
    }

}

address + '-'로 몇번 LBA에 저장되어있는지 파악
SSD클래스 생성자를 이용해 buf를 "00000000"로 초기화, 부분집합을 이용해 숫자값만 buf에 저장 후 result에 저장
"R"을 입력 받을 시 "FULL"인 경우 모두 읽기 "ONE"인 경우 한개만 읽기
std::ios::app 이용 시 기존 파일내용부터 시작
main함수 인자로 argv이용

storage.h

#ifndef __STORAGE_H__
#define __STORAGE_H__

#include <iostream>
#include <stdint.h>

class Storage{
    public:
        virtual void write(uint32_t address, std::string value) = 0;
        virtual void read(uint32_t address, bool flag) = 0;
};

#endif

추상클래스를 이용해 확장성 보장

shell.cpp

#include "val.h"
#include "exefc.h"
#include "fcssd.h"

int main() {
    std::ofstream fout1("nand.txt");
    fout1.close();
    std::ofstream fout2("result.txt");
    fout2.close();

    std::string s, LBA_s, h;
    int LBA;
    while (1) {
        std::cout << "명령어를 입력하세요: ";
        std::cin >> s;

        if (s == "write") {
            std::cin >> LBA_s;
            std::cin >> h;
            if(write(LBA_s, h) == false){
                continue;
            }
        }

        else if (s == "fullwrite") {
            std::cin >> h;
            if(fullwrite(h) == false){
                continue;
            }
        }

        else if (s == "read") {
            std::cin >> LBA_s;
            if(read(LBA_s) == false){
                continue;
            }
        }

        else if (s == "fullread") {
            if(fullread() == false){
                continue;
            }
        }

        else if (s == "help") {
            help();
        }

        else if (s == "exit") break;

        else if(s == "testapp1"){
            std::cin >> h;
            if(fullwrite(h) == false){
                continue;
            }

            if(fullread() == false){
                continue;
            }
        }

        else if(s == "testapp2"){
            for(int i = 0; i < 30; i++){
                for(int j = 0; j < 5; j++){
                    if(write(std::to_string(j), "0xAAAABBBB") == false){
                        continue;
                    }
                }
            }

            for(int i = 0; i < 5; i++){
                if(write(std::to_string(i), "0x12345678") == false){
                    continue;
                }
            }

            for(int i = 0; i < 5; i++){
                if(read(std::to_string(i)) == false){
                    continue;
                }
            }
        }

        else {
            getline(std::cin, s); // 쓰레기값 치우기
            std::cout << "INVALID COMMAND" << std::endl;
        }

    }

    return 0;
}

초기에 파일 초기화
else에서 getline으로 뒤에 입력받은 값 처리
각 기능들 함수로 만들어 testapp구현 시 용이

fcssd.h

#ifndef __FCSSD_H_
#define __FCSSD_H_
#include "exefc.h"
#include "val.h"

bool write(std::string LBA_s, std::string h);
bool fullwrite(std::string h);
bool read(std::string LBA_s);
bool fullread();
void help();
#endif

fcssd.cpp

#include "fcssd.h"

bool write(std::string LBA_s, std::string h){
    int LBA;
    try{
        LBA = std::stoi(LBA_s);
    }
    catch(std::invalid_argument&){
        std::cout << "LBA로 올바른 타입을 입력하세요" << std::endl;
        return false;
    }

    if (isLBA(LBA) == 0) {
        std::cout << "LBA범위 오류" << std::endl;
        return false;
    }

    if (isHexadecimal(h) == 0 || h.size() != 10) {
        std::cout << "16진수 입력 값 오류" << std::endl;
        return false;
    }
    else h = h.substr(2);
    //std::cout << LBA_s << h;
    if(exefc("a.exe", "W", LBA_s, h) == false){
        std::cerr << "\nSSD 실행에 실패했습니다!" << std::endl;
        return false;
    }

    return true;
}

bool fullwrite(std::string h){
    std::ofstream fout1("nand.txt");
    fout1.close(); // 속도저하

    if (isHexadecimal(h) == 0 || h.size() != 10) {
        std::cout << "16진수 입력 값 오류" << std::endl;
        return false;
    }
    for (int i = 0; i < 100; i++) {
        if(exefc("a.exe", "W", std::to_string(i), h) == false){
            std::cerr << "\nSSD 실행에 실패했습니다!" << std::endl;
            return false;
        }
    }
    return true;
}

bool read(std::string LBA_s){
    int LBA;
    std::string line;
    try{
        LBA = std::stoi(LBA_s);
    }
    catch(std::invalid_argument&){
        std::cout << "LBA로 올바른 타입을 입력하세요" << std::endl;
        return false;
    }

    if (isLBA(LBA) == 0) {
        std::cout << "LBA범위 오류" << std::endl;
        return false;
    }

    if(exefc("a.exe", "R", LBA_s, "ONE") == false){
        std::cerr << "\nSSD 실행에 실패했습니다!" << std::endl;
        return false;
    }

    std::ifstream fin("result.txt");
    while (std::getline(fin, line)) {
        std::cout << line << std::endl;
    }
    fin.close();

    return true;
}

bool fullread(){
    std::string line;
    std::ofstream fout("result.txt");
    fout.close(); // 초기화

    for(int i = 0; i < 100; i++){
        if(exefc("a.exe", "R", std::to_string(i), "FULL") == false){
            std::cerr << "\nSSD 실행에 실패했습니다!" << std::endl;
            return false;
        }
    }
    std::ifstream fin("result.txt");
    while (std::getline(fin, line)) {
        std::cout << line << std::endl;
    }
    fin.close();

    return true;
}

void help(){
    std::cout << "====명령어 사용 방법======" << std::endl;
    std::cout << "write: LBA에 입력\n ex) write LBA번호 입력값" << std::endl;
    std::cout << "read: 화면출력\n ex) write LBA번호" << std::endl;
    std::cout << "exit: Shell 종료\n ex) exit" << std::endl;
    std::cout << "help: 명령어 사용방법 출력\n ex) help" << std::endl;
    std::cout << "fullwrite: LBA 0번부터 99번까지 입력\n ex) fullwrite 입력값" << std::endl;
    std::cout << "fullread: LBA 0번부터 99번까지 출력\n ex) fullwrite" << std::endl;
}

유효성검사 + execfc를 이용해 a.exe에 인자 전달

val.h

#ifndef __VAL_H_
#include <cctype>
#include <string>
#include <iostream>
#include <fstream>

bool isHexadecimal(const std::string& input);
bool isLBA(const int& input);
#endif

val.cpp

#include "val.h"

bool isHexadecimal(const std::string& input) {
    // 입력 문자열이 빈 문자열인지 검사
    if (input.empty()) return false;

    // 0x 또는 0X로 시작하면 이를 무시 (16진수 표기법)
    size_t startIndex = 0;
    if (input.length() > 2 && (input[0] == '0') && (input[1] == 'x' || input[1] == 'X')) {
        startIndex = 2;
    }
    else{
        return false;
    }

    // 남은 문자가 모두 16진수 값인지 검사
    for (size_t i = startIndex; i < input.length(); ++i) {
        if (!std::isxdigit(input[i])) {
            return false;
        }
    }
    return true;
}


bool isLBA(const int& input) {
    if (input >= 0 && input < 100) return true;
    else return false;
}

유효성검사

exefc.h

#ifndef __EXEFC_H_
#include <process.h>
#include "val.h"

bool exefc(std::string p_name, std::string ist, std::string LBA, std::string h);
#endif

exefc.cpp

#include "exefc.h"
#include "val.h"

bool exefc(std::string p_name, std::string ist, std::string LBA, std::string h){
    const char* program = p_name.c_str();
    const char* args[] = { program, ist.c_str(), LBA.c_str(), h.c_str(), NULL };
    int result = _spawnvp(_P_WAIT, program, args); // _P_WAIT  _P_NOWAIT

    if (result == -1) return false;
    else return true;
}

인자를 모두 string으로 받은 후 c_str()로 const char*형으로 변환
_P_WAIT를 이용해 a.exe가 끝날 때 까지 기다린 후 종료

추상클래스 사용으로 SSD클래스 외 다른 클래스도 read, write하게 만들고 shell의 기능들을 함수로 만들어 testapp만들 때 편리했다.
main함수로 인자를 받는 argv와 새로운 프로세스를 생성하는 _spawnvp 이용해 2개의 실행파일이 연결되게 했다

profile
생각 정리

0개의 댓글