//Trie

struct trie {
    struct node {
        bool terminal;
        map<char, node*> child;
        node() : terminal(false) {}
    };

    node* head = new node();

    void store(string str) {
        store_dfs(str, 0, head);
    }

    bool find(string str) {
        return find_dfs(str, 0, head);
    }

private:
    void store_dfs(string str, int n, node* now) {
        if(n == str.size()) {
            now->terminal = true;
            return;
        }

        if(now->child.find(str[n]) == now->child.end()) 
            now->child[str[n]] = new node();

        store_dfs(str, n + 1, now->child[str[n]]);
        now->terminal = false;
    }

    bool find_dfs(string str, int n, node* now) {
        if(str.size() == n) return true;
        if(now->terminal) return false;

        bool ret = false;
        for(auto nxt : now->child) {
            if(str[n] == nxt.first)
                ret |= find_dfs(str, n + 1, nxt.second);
        }

        return ret;
    }
};




//Aho-Corasic
struct Aho_Corasic {

    struct node {
        char now_char;
        map<char, node*> child;
        node* fail;
        bool terminal;

        node(char c) {
            now_char = c;
            terminal = false;
        }
        
        ~node() {
        	for(auto it = child.begin(); it != child.end(); it++) delete it->second;
        }
    };

    node* root;
    
    Aho_Corasic() {
        root = new node(' ');
        root->fail = root;
    }

    ~Aho_Corasic() {
        delete root;
    }

    void insert(string str) {
        node* now = root;
        for(char c : str) {
            if(now->child.find(c) == now->child.end()) now->child[c] = new node(c);
            now = now->child[c];
        }
        now->terminal = true;
    }

    void failure() {
        queue<node*> q;
        root->fail = root;
        q.push(root);

        while(!q.empty()) {
            node* now = q.front(); q.pop();
            for(auto it = now->child.begin(); it != now->child.end(); it++) {
                node* next = it->second;
                char next_char = next->now_char;
                if(now == root) {
                    next->fail = root;
                }
                else {
                    node* failnode = now->fail;

                    while(failnode != root && failnode->child.find(next_char) == failnode->child.end()) {
                        failnode = failnode->fail;
                    }
                    if(failnode->child.find(next_char) != failnode->child.end()) {
                        failnode = failnode->child[next_char];
                    }

                    next->fail = failnode;
                }
                if(next->fail->terminal) next->terminal = true;
                q.push(next);
            }
        }
    }

    bool query(string str) {
        node* now = root;

        for(char c : str) {
            while(now != root && now->child.find(c) == now->child.end())
                now = now->fail;
            if(now->child.find(c) != now->child.end()) now = now->child[c];
            if(now->terminal) return true;
        }

        return false;
    }
};



//최소 공통 조상(LCA);
const int MN = 100001;
vector<int> g[MN];

int h[MN];
int dp[20][MN];

void dfs(int n, int prev) {
    for(int nxt : g[n]) {
        if(nxt == prev) continue;
        h[nxt] = h[n] + 1;
        dp[0][nxt] = n;
        dfs(nxt, n);
    }
}

int LCA(int a, int b) {
    if(h[a] < h[b]) swap(a, b);

    int gap = h[a] - h[b];

    for(int i = 0; i < 20; i++)
        if(gap & (1 << i))
            a = dp[i][a];

    if(a == b) return a;

    for(int i = 19; i >= 0; i--)
        if(dp[i][a] != dp[i][b])
            a = dp[i][a], b = dp[i][b];

    return dp[0][a];
}

int main() {
    ios::sync_with_stdio(false); cin.tie(NULL);

    int N; cin >> N;
    for(int i = 0; i < N-1; i++) {
        int u, v; cin >> u >> v;
        g[u].push_back(v);
        g[v].push_back(u);
    }

    dfs(1, 0);

    for(int i = 1; i < 20; i++)
        for(int j = 1; j <= N; j++)
            dp[i][j] = dp[i-1][dp[i-1][j]];

    int M; cin >> M;
    while(M--) {
        int a, b; cin >> a >> b;
        cout << LCA(a, b) << '\n';
    }
}

OS는 굉장히 큰 프로그램이다. 따라서 역할별로 계층이 나누어져 있다.

Windows, Linux, Mac OS 등 각 운영체제마다 다양한 구조를 가지고 있다. 

운영체제의 구조의 종류는 다음과 같다.

 

1. Simple Structure

  • 기능적으로 구역을 나누어져 있다.
  • module 단위로 나누어지지 않는다.
  • 인터페이스와 기능의 레벨이 잘 분리되어 있지 않다.
  • MS DOS가 이런 구조로 이루어져 있다.

2. Monolithic Structure

  • 시스템 프로그램과 커널로 이루어져 있다.
  • 커널은 사용자, 프로그램과 system call interface를 통해 소통한다.
  • 각 device controller와 kernal interface를 통해 소통한다.
  • file system, CPU scheduling, 메모리 관리 등의 모든 기능이 하나의 레벨에 존재한다.
  • 따라서 일부를 고치면 프로그램 전체를 고쳐야 하는 단점이 있다.
  • UNIX가 이런 구조로 되어 있다.

3. layered approach

  • 각 층의 독립성을 높였다.
  • 모듈화를 통해 각 계층은 바로 아래 계층에서 제공하는 기능과 서비스만 사용하므로 어떻게 구현되었는 지는 알 필요가 없다.
  • 이런 구조로 구축, 디버깅이 단순하고 설계와 구현이 쉽다는 장점이 있다.
  • 하지만 각 계층의 기능을 명확히 정의하기 어렵고 오직 하위 계층의 기능만 사용하기 때문에 주의 깊은 설계가 필요하고 순서대로 기능이 수행되므로 효율성이 떨어진다는 단점이 있다.
  • Solaris 초기 구조이다.

4. Microkernel(Mach)

  • 커널의 많은 부분을 user space에서 수행하도록 했다.
  • User module 간에 message passing 방식을 이용하여 통신한다.
  • 확장이 쉽고 OS를 새로운 구조로 만들기 쉽고 커널에서 돌아가는 코드가 적기 때문에 신뢰적이고 안전하다는 장점이 있다.
  • User space와 Kernel space 간의 통신의 overhead가 크다는 단점이 있다.
  • Mach 커널이 Microkernel 중 하나이다. Mac OS X의 kernel인 darwin의 일부를 mach 커널 기반으로 만들었다.

5. Modules

  • 기능 단위로 모듈을 구성한다.
  • layered와 비슷하지만 더 flexible하다.
  • 커널 내 통신이 빠르다.
  • monolithic 방식은 업데이트가 너무 어렵기 때문에 기능 단위로 module을 구성하고 이 module들이 모여 하나의 kernel 서비스를 제공한다.
  • 현재 OS는 loadable kernel modules를 사용한다.
    • 객체지향 방식의 접근법을 사용하였다.
    • 각 핵심 component가 분리되어 있다.
    • 서로 정의된 interface를 통해 통신한다.
    • kernel에서 필요할 때 load된다.
  • linux가 이런 방식을 사용한다.

6. Hybrid Systems

    • 성능, 보안, 실용성을 위해 여러 가지를 조합하여 커널을 구성한다.
    • Linux, solarismonolithicmodular를 더한 커널을 사용
    • 윈도우는 monolithic 기반에 다른 서브시스템의 개성을 위해 microkernel을 사용한다.
    • MAC OSmach커널에 BSD커널이 hybrid형태로 되어 있는 darwin커널을 제공. 각각 따로 인터페이스가 이루어져 있다.

 

IOS와 Android

 - IOS

  • darwin 커널에 근간하여 OS X와 동일한 커널을 사용하지만 OS X의 프로그램이 동작하지는 않는다. CPU 구조도 다르기 때문에 돌아갈 수 없다.
  • 어플 개발을 위해 cocoa touch라는 API를 제공하는 계층이 있다.
  • 그래픽, 오디오, 비디오를 위한 media service를 제공하는 계층이 있다.
  • 클라우드 컴퓨팅, 데이터 베이슬르 위한 Core service 계층이 있다.
  • linux 기반의 core os 계층이 맨 아래에 있다.

 - Android

  • Google에서 만든 오픈소스이다.
  • 모바일 어플케이션 개발으리 위한 framework를 제공하는 S/W 계층이 있다는 점이 IOS와 유사하다.
  • 제일 하위 계층은 Linux 커널 기반으로 프로세스, 메모리, 장치 드라이버 지원과 전력 관리 기능이 추가되었다.
  • n안드로이드 실행환경은 라이브러리와 dalvik 가상 기계를 포함한다. java의 바이트 코드가 컴파일되고 dalvik 가상기계에서 실행된다.
  • linux kernel과 libraris 사이에 하드웨어에 관계 없이 상위 계층이 동작하도록 추상화한 HAL계층이 있다.

운영체제(Operating Sysetm)는 컴퓨터 사용자가 하드웨어를 잘 사용할 수 있도록 도와주고 하드웨어 자원을 관리하는 시스템 프로그램이다. 운영체제가 제공하려는 서비스의 목적은 다음과 같다.

  • 환경 제공 : 사용자가 컴퓨터 시스템을 편리하게 사용할 수 있는 환경을 제공한다.
  • 프로세스 제어 관리 : 사용자 프로그램을 효율적으로 실행시켜 사용자 문제를 좀 더 쉽게 해결한다.
  • 자원 관리 : 컴퓨터 하드웨어를 효율적인 방법으로 사용할 수 있게 한다.

위 세 가지 이외에도 사용자에게 편리한 인터페이스를 제공하기도 하고 저전력으로 OS를 동작할 수 있게 하는 등의 여러가지 기능을 제공한다.

 

컴퓨터 시스템의 동작

  • 속도가 느린 I/O device와 속도가 빠른 CPU가 동시에 동작할 수 있도록 한다.
  • 각 device driver는 특정한 디바이스를 담당하고 자신마의 buffer를 가진다.
  • CPU가 데이터를 main memory에서 device의 buffer로 쓰거나 읽도록 명령을 내린다.
  • 입출력 요청을 device에서 controller의 buffer로 보낸다.
  • Device controller는 CPU에게 interrupt를 보내면서 작업이 끝났다는 것을 알린다.

컴퓨터 시스템에서 발생하는 interrupt는 다음과 같이 두 가지 종류가 있다.

  • H/W interrupt : CPU의 pin에서 신호를 일으켜서 발생한다. I/O device와 관련이 있다.
  • S/W interrupt : OS가 발생시키는 interrupt이다. trap이라고도 하며 division by zero와 같은 run time error가 해당된다.

OS가 사용자나 프로그램이 프로그램을 실행할 수 있도록 제공하는 환경

  • User interface
  • Program execution
  • I/O operation

OS가 사용자를 위해 제공하는 기능

  • File-system manipulstion
  • communications
  • Error detection

OS가 효율적인 OS 시스템 자체를 위해 제공하는 기능

  • Resource allocation
  • accounting
  • protection and security

컴퓨터 시스템은 크게 3가지의 컴포넌트로 구성된다. 이 세 가지 컴포넌트는 다음과 같다.

  • 하드웨어 : 기본적인 컴퓨팅적 자원을 제공한다. Ex) CPU, 메모리, I/O 장치
  • 운영체제 : 여러가지 어플리케이션과 사용자 간의 하드웨어의 사용을 제어한다. HW와 어플리케이션 프로그램 사이에 중간 다리 역할을 한다.
  • 어플리케이션 프로그램 : 시스템 자원을 사용하여 사용자의 컴퓨팅적인 문제를 해결한다. Ex) 워드 프로세서, 웹 브라우저, DB 시스템, 비디오 게임

컴퓨터를 시작하는 프로세스 : Bootstrap

  1. bootstrap은 컴퓨터 전원을 켜거나 재부팅을 할 때 메모리에 load된다.
  2. bootstrap은 일반적으로 firmware로 알려져 있는 ROM이나 EEPROM에 주로 저장되어있다.
  3. 시스템을 초기화하고 필요한 하드웨어를 확인한다.
  4. OS 커널을 메인 메모리에 올리고 실행한다.

컴퓨터가 실행되는 과정(부트로더 흐름)

      1. 전원을 켜거나 재부팅할 경우 ROM BIOS가 먼저 실행된다. bootstrap은 BIOS의 일부분이다.
      2. BIOS는 HW적으로 오류가 있는지 확인한다 (POST : power on self test라고도 한다).
      3. BIOS가 디스크의 sector 1번인 Master Boot Record를 읽어온다. MBR에 부트로더가 존재한다.
      4. 부트로더의 GPIO 설정, 클록 활성화, RAM 설정, 부팅 루틴 복사 등을 한다.
      5. 부트로더가 UART(universal asynchronous receive and transmit), 타이머, 플래시, 이더넷 등을 초기화한다.
      6. 자동 부팅 메시지를 출력하고 임의의 키를 입력하면 수동 부팅 모드(명령어 모드)로 실행하고 그게 아니면 자동 부팅모드로 실행한다.
      7. Boot loader가 커널이 올라가야 할 메모리의 위치에 이미지를 올리면 1번 프로세스부터 동작하고 OS가 동작한다.

부트로더는 assembler와 C언어로 구성되어 있다. HW와 더 가까운 작업은 assembler가 수행한다.

'운영체제' 카테고리의 다른 글

[OS] 여러 가지 운영체제 구조  (0) 2021.12.30
[OS] 운영체제의 기능과 목적  (0) 2021.12.30

https://www.acmicpc.net/problem/15684

 

15684번: 사다리 조작

사다리 게임은 N개의 세로선과 M개의 가로선으로 이루어져 있다. 인접한 세로선 사이에는 가로선을 놓을 수 있는데, 각각의 세로선마다 가로선을 놓을 수 있는 위치의 개수는 H이고, 모든 세로선

www.acmicpc.net

 

풀이

    문제의 입력을 보면 세로선의 개수는 최대 10개, 높이는 최대 30개이다. 즉 놓치 못하는 규칙을 고려하지 않았을 때 가로선이 있을 수 있는 위치는 총 300개이다. 또 최대 3개의 가로선을 추가할 수 있는 조건을 보았을 때 브루트 포스 알고리즘으로 백트래킹을 사용해도 풀릴 수 있는 문제라고 생각하였다. 따라서 가로선이 놓일 수 있는 부분이 겹치지 않게 놓다보면 시간초과가 발생하지 않을 것이다.

    가로선은 세로선에서 오른쪽으로만 놓는다고 생각한다. 따라서 j번 세로선에 놓는다고 했을 때 j-1, j+1의 세로선에 모두 가로선이 존재하지 않아야한다. 만약 j번에 놓을 수 있을 때 dfs를 이용하여 재귀적으로 j번 세로줄부터 놓을 수 있는 위치를 다시 계산한다. 최대한 중복을 줄이기 위해 j번 세로줄부터 확인하는 것이다.

 

소스 코드

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <deque>

using namespace std;

const int MN = 9;
int N, M, H;
int ans = 4; //최대 3까지이므로 4로 설정

void dfs(int now, int n, bool ladder[31][11]) {
    if(n >= ans) return; //이미 최소값을 넘은 경우 탐색하지 않음

    bool chk = false; //모두 j번 세로줄이 j번에서 끝나는지 확인하는 변수
    for(int j = 1; j <= N; j++) {
        int now = j;
        for(int i = 1; i <= H; i++) {
            if(ladder[i][now-1]) { //왼쪽에 길이 있다면 왼쪽 세로줄로 이동
                now--;
            }
            else if(ladder[i][now]) { //오른쪽에 길이 있다면 오른쪽 세로줄로 이동
                now++;
            }
        }
        if(now != j) { //만약 j번에서 끝나지 않은 경우
            chk = true; //끝나지 않음을 체크 후 종료
            break;
        }
    }
    if(!chk)  { //만약 모두 알맞게 끝난 경우
        ans = min(ans, n); //최소값 갱신 후 더 이상 탐색하지 않음
        return;
    }

    if(n == 3) return; //3개 가로줄 사용한 경우 리턴
    for(int j = now; j < N; j++) { //지금까지 탐색한 세로줄부터
        for(int i = 1; i <= H; i++) { //모든 높이를 탐색
            if(!ladder[i][j] && !ladder[i][j+1] && !ladder[i][j-1]) { //가로줄을 놓을 수 있는 경우
                ladder[i][j] = true; //가로줄 생성
                dfs(j, n+1, ladder); //재귀
                ladder[i][j] = false; //가로줄 제거
            }
        }
    }
}

int main() {
    cin >> N >> M >> H;
    bool ladder[31][11];
    memset(ladder, 0, sizeof(ladder)); //사다리 초기화
    for(int i = 0; i < M; i++) {
        int a, b; cin >> a >> b;
        ladder[a][b] = true; //가로줄 추가
    }
    dfs(1, 0, ladder); //재귀로 탐색
    if(ans == 4) cout << -1; //방법이 없는 경우 -1출력
    else cout << ans;
}

위 과정대로 작성한 코드이다. 방법이 없는 경우를 고려해 초기값을 4로 설정했다. 최대 3까지 정답이 될 수 있기 때문이다.

 

채점 결과

https://www.acmicpc.net/problem/14891

 

14891번: 톱니바퀴

총 8개의 톱니를 가지고 있는 톱니바퀴 4개가 아래 그림과 같이 일렬로 놓여져 있다. 또, 톱니는 N극 또는 S극 중 하나를 나타내고 있다. 톱니바퀴에는 번호가 매겨져 있는데, 가장 왼쪽 톱니바퀴

www.acmicpc.net

 

문제는 길기 때문에 위 링크에서 확인하길 바란다.

 

풀이

입력이 string으로 주어진다. 톱니바퀴는 4개로 고정이므로 4개의 입력을 받고 K개의 회전을 입력받는다. 이때 회전하는 톱니의 왼쪽, 오른쪽을 구분하여 계산한다. 알고리즘의 동작 순서는 다음과 같다.

  • 돌리는 톱니의 왼쪽부터 확인한다.
  • 현재 톱니는 돌리는 톱니이다.
  • 만약 맞물리는 부분이 상극인 경우 현재 톱니를 어느 방향으로 돌리는지 배열에 표시하고 왼쪽 톱니가 현재 톱니가 된다.
  • 끝까지 가거나 맞물리는 부분이 상극이 아니어 회전하지 않을 때까지 반복한다.
  • 오른쪽 부분도 같은 과정을 진행한다.
  • 회전하는 방향을 표시해놓은 배열을 보며 톱니를 회전시킨다. 0인 경우 회전하지 않고 1인 경우 시계방향, -1인 경우 반시계방향으로 회전한다.
  • K번의 회전이 끝난 후 12시에 있는 극이 무엇인지 보고 결과값을 출력한다.

 

소스 코드

#include <iostream>
#include <string>
#include <cstring>
#include <vector>
#include <deque>

using namespace std;

const int MN = 101;
string wheel[5]; //1~4까지 톱니의 번호
int main() {
    cin >> wheel[1] >> wheel[2] >> wheel[3] >> wheel[4]; //4가지 톱니를 입력받음
    int K; cin >> K;
    int rotation[5]; //회전을 표시하는 배열
    for(int i = 0; i < K; i++) {
        memset(rotation, 0, sizeof(rotation)); //배열 초기화
        int num, direction; cin >> num >> direction;
        rotation[num] = direction; //현재 톱니의 회전 방향 체크
        //회전하는 톱니 왼쪽
        int now = num; //현재 톱니
        int nowd = direction; //현재 방향
        for(int w = num-1; w > 0; w--) {
            if(wheel[now][6] != wheel[w][2]) { //상극인 경우
                rotation[w] = -nowd; //반대 방향으로 회전 표시
                nowd = -nowd; //현재 방향 수정
                now--; //다음 톱니로 이동
            }
            else { //같은 극인 경우
                rotation[w] = 0; //회전하지 않는다고 표시 후 종료
                break;
            }
        }
        //회전하는 톱니 오른쪽
        now = num; //현재 톱니
        nowd = direction; //현재 방향
        for(int w = num+1; w <= 4; w++) {
            if(wheel[now][2] != wheel[w][6]) { //상극인 경우
                rotation[w] = -nowd; //반대 방향으로 회전 표시
                nowd = -nowd; //현재 방향 수정
                now++; //다음 톱니로 이동
            }
            else { //같은 극인 경우
                rotation[w] = 0; //회전하지 않는다고 표시 후 종료
                break;
            }
        }
        

        //톱니바퀴 회전시키기
        for(int j = 1; j <= 4; j++) {
            if(rotation[j] == 0) continue; //회전하지 않는 경우 건너뛰기
            if(rotation[j] == 1) { //시계방향으로 회전하는 경우
                string tmp = wheel[j].substr(0, 7);
                wheel[j] = wheel[j][7] + tmp;
            }
            else if(rotation[j] == -1) { //반시계방향으로 회전하는 경우
                string tmp = wheel[j].substr(1);
                wheel[j] = tmp + wheel[j][0];
            }
        }
    }
    //결과 계산
    int ans = 0;
    if(wheel[1][0] == '1') ans++; 
    if(wheel[2][0] == '1') ans +=2;
    if(wheel[3][0] == '1') ans += 4;
    if(wheel[4][0] == '1') ans += 8;

    cout << ans;
}

위 풀이를 그대로 구현한 코드이다.

 

채점 결과

개발환경

  • Windows 10 pro 64bit
  • Visual studio 2019(Intel(R) C++ Complier)
  • Visual Studio Code (version 1.59.0)
  • Node.js (version 14.16.0)
  • Jupyter Notebook
  • dlib (version 19.22.1)
  • OpenCV
  • React (version 17.0.2)
  • Ubuntu (version 20.04)
  • oracle cloud
  • Django (version 3.2.6)

 

소스 코드

https://github.com/Seo-sang/Stroke_Self_Diagnosis

 

GitHub - Seo-sang/Stroke_Self_Diagnosis

Contribute to Seo-sang/Stroke_Self_Diagnosis development by creating an account on GitHub.

github.com

위 링크의 장고 웹서버를 포함한 모든 소스코드는 django2 branch에 존재한다.

master branch에는 리액트 프론트엔드와 머신러닝을 활용한 학습 및 예측하는 코드가 존재한다.

 

느낀점

    이번 공모전을 통해 오픈소스를 실제로 사용해보고 깃허브를 통해 팀원들과 한 repository에 push, pull하며 함께 프로그램을 만들고 실수도 많이 해보며 많이 배울 수 있었고 여러가지 오류들을 접하며 구글링을 통해 대처하고 해결하는 능력도 키울 수 있었던 것 같다.

    여러가지 프로그램을 설치해야하고 팀원과의 환경이 달라 내 PC에서는 동작하지 않은 문제들을 접하며 다른 사람들이 동작시킬 때에도 무엇이 문제가 될지를 생각해볼 수 있었다. 또 http를 사용할 때 보안문제로 인해 웹캠이 실행되지 않은 문제가 있었다. 따라서 localhost를 이용할 때는 문제가 없었지만 외부망에서 접속할 때 문제가 생겼다. 이를 해결하기 위해선 ssh로 접속해야하는 부분을 추가해야하지만 이 부분까지는 고려하지 못했다. 계속 수정할 계획이기 때문에 해결될 경우 다시 글을 적어보도록 하겠다.

    많은 것을 배울 수 있는 공모전이었고 동기들과 팀을 이뤄 원했던 결과가 딱 뜨는 순간 희열을 느낄 수 있었다. 마무리를 할 수 있어 굉장히 뿌듯했고 다음 번에는 또 다른 주제로 공모전에 참가해보도록 하겠다.

 

시연 영상

https://www.youtube.com/watch?v=i8v_ckeE2G4 

 

이번에는 장고 프레임 워크를 활용하여 벡엔드를 구현한 기능에 대하여 설멍하겠다. 저번 글에서 리액트를 활용하여 프론트엔드를 구현하였고 프론트엔드로부터 받은 사진을 백엔드에서 처리한 후 결과를 다시 프론트엔드로 보여주는 과정이 필요하다. 백엔드를 구현하는데에는 장고라는 python 프레임워크를 이용하였다. 장고의 구성도는 다음과 같다

. 주 역할

  • 홈페이지 파일 클라이언트에 http로 전송
  • 홈페이지와 서버 내부의 뇌졸중 여부 판단 함수 사이에 주고 받아야 하는 값 네트워크 통신을 통해 전달
  • 이목구비 구분 이미지 서버 내부에 저장

 

프로젝트 내 포함 파일

  • 홈페이지를 구성하는 리액트 앱 및 자바스크립트 파일
  • 홈페이지와 통신하는 장고 stroke앱 및 파이썬 파일
  • 얼굴 인식 및 뇌졸중 판단 여부 확인 함수의 results.py, train.py
  • 홈페이지에 나타낼 이목구비 구분 이미지 파일 (사진을 업로드 할 때 마다 저장)
  • 그 외 미디어 파일 및 정적 파일 (배경 사진, 정적 이미지)

 

프로젝트 수행 순서 (장고 위주 기술)

  1. 장고 프로젝트(리액트 앱) 내에 존재하는 index.html 파일을 views.py를 통해 클라이언트에게 http로 return한다.
  2. return 받은 index.html로 홈페이지를 출력한다. (리액트가 index.html을 이용하여 홈페이지 출력한다.)
  3. 홈페이지에서 장고 서버에 ip(고유 정보)와 이미지 파일(base64타입)을 post요청한다.
  4. post request를 통해 전달 받은 데이터를 views.py에서 results.py로 전달한다.
  5. results.py에서 연산한 결과값(1)을 json으로 직렬화하여 jsonrepsonse로 홈페이지에 리턴한다.

(1) 뇌졸중 여부, 이목구비 구분된 이미지, 코 중앙에서부터 양쪽 눈 끝으로 각각 이었을 때의 길이 비율, 양쪽 입술 끝으로 이었을 때의 길이 비율, 양쪽 코 끝으로 이었을 때의 길이 비율

 

로컬 호스트 서버 구동

manage.py를 실행하며 장고 서버가 동작한다.

서버 구동 이후

localhost:8000에 접속할 경우 장고에서 리턴하는 홈페이지에 접속 가능하다.

실제 서버에서는 nginx를 이용하여 서버를 구동한다.

정상적인 이미지를 넘겨 받아 뇌졸중 확인을 한 경우 서버 로그에 얼굴 비율 값에 대한 로그를 남깁니다.

+ Recent posts