본문 바로가기

블록체인_9기/💚 Node.js

26강(과제X)_230501_Nodejs(HTTP프로토콜, fs모듈, npm, mysql 연결)

728x90

 

 

 

 


HTTP 프로토콜

  • 우리가 브라우저에서 url을 입력하고 엔터를 누르면 HTT 요청을 보내게 되는데 TCP 3-way handshake과정을 거친다.
  • 플래그 정보
    • SYN(Synchronize Sequence Number) / 000010
      • 연결 설정. Sequence Number를 랜덤으로 설정하여 세션을 연결하는 데 사용하며, 초기에 Sequence Number를 전송한다.
    • ACK(Acknowledgement) / 010000
      • 응답 확인. 패킷을 받았다는 것을 의미한다.
      • Acknowledgement Number 필드가 유효한지를 나타낸다.
      • 양단 프로세스가 쉬지 않고 데이터를 전송한다고 가정하면 최초 연결 설정 과정에서 전송되는 첫 번째 세그먼트를 제외한 모든 세그먼트의 ACK 비트는 1로 지정된다고 생각할 수 있다.
    • FIN(Finish) / 000001
      • 연결 해제. 세션 연결을 종료시킬 때 사용되며, 더 이상 전송할 데이터가 없음을 의미한다.

 

TCP 3-way handshake

  • TCP 통신을 이용하여 데이터를 전송하기 위해 네트워크 연결을 설정(Connection Establish) 하는 과정
  • 양쪽 모두 데이터를 전송할 준비가 되었다는 것을 보장하고, 실제로 데이터 전달이 시작하기 전에 한 쪽이 다른 쪽이 준비되었다는 것을 알 수 있도록 한다.
  • 즉, TCP/IP 프로토콜을 이용해서 통신을 하는 응용 프로그램이 데이터를 전송하기 전에 먼저 정확한 전송을 보장하기 위해 상대방 컴퓨터와 사전에 세션을 수립하는 과정을 의미한다.

작동방식

  • client는 server와 연결하기 위해 TCP 3-way handshake를 통해 연결을 요청한다.
  • client와 server는 모두 서로 연결요청을 할 수 있다. 연결요청을 먼저 시도한 요청자를 client, 연결 요청을 받은 수신자를 server로 보면 된다.
  1. client는 server와 연결하기 위해 SYN을 보낸다.
  2. server는 SYN을 받고 client로 받았다는 신호인 ACK와 SYN을 보낸다.
    1. 접속요청을 받은 server가 요청을 수락했으며, client도 포트를 열어달라는 메시지를 전송한다.
  3. client는 server로부터 받은 ACK와 SYN을 받고 ACK를 보낸다.
    1. 마지막으로 client가 수락확인을 보내 연결을 맺는다.
    2. 이때, 전송할 데이터가 있으면 이 단계에서 데이터를 전송할 수 있다.

 

TCP 4-way handshake

  • 4-Way Handshake은 연결을 해제 (Connecntion Termination)하는 과정이다. 여기서는 FIN 플래그를 이용한다.

작동방식

  • client와 server는 모두 서로 연결요청을 할 수 있다. 연결요청을 먼저 시도한 요청자를 client, 연결 요청을 받은 수신자를 server로 보면 된다.
  1. server와 client가 연결된 상태에서 클라이언트가 연결을 종료한다는 FIN을 보내며 접속을 끊는다.
  2. server는 FIN을 받고 데이터가 없다는 것을 의미하는 ACK를 보낸다.
    1. server는 client에게 응답을 보내고 남은 데이터가 있다면 마저 전송을 마친다.
    2. client는 server에서 ACK를 받은 후에 server가 남은 데이터 처리를 끝내고 FIN 패킷을 보낼때까지 기다린다.
  3. server는 데이터를 모두 보낸 후, 연결 종료에 합의한다는 의미로 FIN을 client에게 보낸다.
  4. client는 FIN을 받고 확인했다는 ACK를 server에 보낸다.

 

HTTP 프로토콜을 이용한 웹서버 개발

1. HTTP 모듈을 선언

  • 내장 모듈인 http 모듈을 사용한다.
    • 요청과 응답을 처리하는 기능을 제공하는 모듈이다.
const exem = require("http");

2. 서버 객체 생성

  • createServer메소드: 서버 객체를 만들어준다. 매개변수로 전달되는 콜백함수에는 매개변수로 req, res를 전달해준다.
    • req: http 요청의 정보. url, 메소드(GET, POST 등) 요청 헤더 정보, 바디의 내용이 있다.
    • res: http 응답의 정보. 상태코드는 statusCode, 응답헤더, 바디의 내용이 있다.
  • res.setHeader: 응답 헤더의 내용을 설정할 수 있다.
    • Content-Type: 응답의 내용
    • application/json: 응답의 내용을 JSON 형식의 데이터로 전송
    • charset=utf-8: 응답의 문자를 인코딩. utf-8로 설정
  • res.end: 내용을 응답하고 종료하는 메소드
    • 응답하는 내용은 매개변수로 전달하면 된다.
    • 매개변수의 내용을 브라우저 내용으로 확인할 수 있다.
  • 파비콘 요청을 무시하기
    • 브라우저에 요청을 보내면 웹사이트의 아이콘인 파비콘의 url이 자동으로 요청된다. 해당 부분을 무시하는 방법이 있다.
// 파비콘 무시 처리를 헤주자.
if(URL === "/favicon.ico"){
    res.end();
    return;
}
const server = exem.createServer((req, res)=>{

    // statusCode 200 == 성공
    res.statusCode = 200;

	res.setHeader("Content-Type", "application/json", "charset=utf-8");
    
    // 요청한 URL은 뭐지?
    const URL = req.url;
    console.log(URL)        //브라우저에서 요청한 url의 값이 콘솔로 뜬다.

    // /: main 페이지의 경로
    // /list: 글의 목록 페이지 혹은 게시판
    // /add: 글을 추가하는 페이지

    // 파비콘 무시 처리
    if(URL === "/favicon.ico"){
        res.end();
        return;
    }
    
    console.log(URL);

    switch (URL) {
        case "/":
            res.end("main page")
            break;
        case "/list":
            res.end("list page")
            break;
        case "/add":
            res.end("add page")
            break;
    }

})

3. 서버 대기 상태

  • listen메서드로 첫 번째 매개변수 exem서버를 대기 상태로 만들어 놓자
server.listen(4000, ()=>{
    console.log("서버 잘 열렸음")
})

 

 

 

 


fs 모듈

  • 파일 입출력 처리를 할 때 사용하는 모듈
  • 파일을 생성, 삭제, 읽기 쓰기 등의 작업을 할 수 있다.

fs모듈 불러오기

  • 내장 모듈이므로, 별도의 라이브러리 없이 바로 불러서 사용 가능하다.
const fs = require("fs");

 

existsSync_폴더 존재 유무 확인

  • 파일이 주어진 경로에 이미 존재하는지 여부를 동기적으로 확인하는데 사용하는 메소드
    • ' Sync ' 구문이 있는 메소드는 동기적으로 작동한다.
  • 반환값은 true,false를 가진다.
let folder = fs.existsSync("./Test");
console.log(folder);
/*결과
폴더가 있을 경우: true
폴더가 없을 경우: false */

 

mkdir 또는 mkdirSync_폴더 생성

  • mkdir: 폴더를 비동기적으로 생성하는 메소드이다.
    • 첫 번째 매개변수: 생성할 폴더의 경로를 입력
    • 두 번째 매개변수: 폴더 생성 시 호출할 콜백함수
      • 콜백함수의 첫 번째 매개변수: 에러의 내용
  • mkdirSync: 폴더를 동기적으로 생성하는 메소드이다.
if (!folder) {
    // mkdir: 비동기적으로 실행
    fs.mkdir("./Test", (err) => {
        if (err) {
            console.log(err)
            console.log("에러남");
        }
        else {
            console.log("Test 폴더 잘 만들어짐")
        }
    })
    // mkdirSync: 동기적으로 실행
    fs.mkdirSync("./Test");
    console.log("폴더 잘 만들었음")
}

 

writeFile 또는 writeFileSync_파일 추가

  • writeFile: 파일을 비동기적으로 쓸 수 있는 메소드. 파일에 데이터를 작성할 수 있다.
    • 첫 번째 매개변수: 파일의 이름 경로
    • 두 번째 메개변수: 파일에 작성할 내용
    • 세 번째 매개변수: 콜백함수
      • 콜백함수의 매개변수는 에러 내용의 객체를 전달 받는다.
  • writeFileSync: 파일을 동기적으로 쓸 수 있는 메소드
// 비동기적으로 들어간다.
fs.writeFile("./Test/temp.txt", "Hello nodejs", (err)=>{
    if(err){
        console.log(err)
    }
    else{
        console.log("파일이 잘 만들어졌다.")
    }
})

// 동기적으로 실행되는 메소드
fs.writeFileSync("./Test/temp.txt", "Hello nodejs")

 

readFile 또는 readFileSync_파일 내용 읽기

  • readFile: 파일을 비동기적으로 읽어주는 메소드.
    • 첫 번째 매개변수: 파일의 경로
    • 두 번째 매개뱐수: 인코딩의 내용
      • 인코딩 내용을 작성하지 않으면 자동으로 null이 출력된다.
      •  null은 buffer객체로 읽어온다.
    • 세 번째 매개변수: 콜백함수
      • 콜백함수의 첫 번째 매개변수: 에러의 내용을 객체
      • 콜백함수의 두 번째 매개변수: 읽어온 파일의 내용
  • readFileSync: 동기적으로 파일을 읽어오는 메소드
    • 동기적으로 실행하기 때문에 콜백이 필요없다.
    • 메소드의 반환값으로 파일을 읽러온 data가 나온다.
// 비동기적으로 파일을 읽어오는 메소드
fs.readFile("./Test/temp.txt", "utf-8",(err,data)=>{
    if(err){
        console.log(err);
    }
    else{
        console.log(data);
    }
})

// 동기적으로 파일을 읽어오는 메소드
let data = fs.readFileSync("./Test/temp.txt","utf-8");

 

rm_파일을 제거하는 메소드

  • rm: 폴더를 삭제한다.
    • 첫 번째 매개변수: 삭제할 폴더의 경로
    • 두 번째 매개변수: 옵션 객체를 전달하는데 {recursive : true}
      • recursive 키의 값에 따라 true나 false를 전달해주는데 폴더 안의 내용까지 제거할 것인지 결정한다.
    • 세 번째 매개변수: 콜백함수
      • 콜백함수는 매개변수로 에러 내용의 객체를 전달받는다.
fs.rm("./Test",{recursive : true},(err)=>{
    if(err){
        console.log("err")
        console.log("에러났음")
    }
    else{
        console.log("폴더 잘 삭제함")
    }
})

 

내장 모듈 http & fs를 이용하여 웹 서버 생성

  • views 폴더에 'main.html', 'list.html', 'add.html'을 생성하고 코드를 실행한다.

main.html 또는 list.html 또는 add.html

<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <!-- main page의 경우 -->
    <title>main page</title>
    <!-- list page의 경우 -->
    <title>list page</title>
    <!-- add page의 경우 -->
    <title>add page</title>
</head>
<body>
    <!-- main page의 경우 -->
    <h1>메인 페이지</h1>
    <!-- list page의 경우 -->
    <h1>리스트 페이지</h1>
    <!-- add page의 경우 -->
    <h1>추가 페이지</h1>
</body>
</html>

 

index.js

// 내장모듈 http, fs
const http = require("http");
const fs = require("fs");

const server = http.createServer((req,res)=>{
    // createServer 메서드 서버 객체 만들고
    // 콜백 함수의 매개변수로 req 요청 내용을 가지고 있는 객체
    // res 응답 내용을 가지고 있는 객체를 전달 받는다.

    // setHeader: 응답 헤더내용 설정
    res.setHeader("Content-Type", "application/json", "charset=utf-8");

    // 요청한 url이 뭘까?
    const URL = req.url;

    // 요청한 url이 파비콘이면 그냥 무시
    if(URL === "/favicon/ico"){
        res.end();
        // end(): 내용을 응답하고 종료하는 메소드
        // 응답을 안해주면 클라이언트는 요청을 하고 계속 기다림.
        return;}

    // 요청한 URL의 내용에 따라서 응답
    switch (URL) {
        case "/":
            fs.readFile("./views/main.html",(err,data)=>{
                if(err){
                    // 에러가 나면 파일을 못 불러왔네?
                    // 404: 파일을 불러오지 못했어
                    res.statusCode = 404;
                    res.end("파일 없어....")}
                else{
                    // 파일 잘 가져왔으면
                    res.statusCode = 200;
                    // 전달하는 컨텐츠의 내용은 html 파일의 내용이다.
                    res.setHeader("Content-Type", "text/html");
                    res.end(data);}})
            break;
        case "/list":
            fs.readFile("./views/list.html",(err,data)=>{
                if(err){
                    res.statusCode = 404;
                    res.end("파일 없어!")}
                else{
                    res.statusCode = 200;
                    res.setHeader("Content-Type", "text/html");
                    res.end(data)}})
            
            break;
        case "/add":
            fs.readFile("./views/add.html",(err,data)=>{
                if(err){
                    res.statusCode = 404;
                    res.end("파일 없어!")}
                else{
                    res.statusCode = 200;
                    res.setHeader("Content-Type", "text/html");
                    res.end(data)}})
            break;}

});

server.listen(4000, ()=>{
    console.log("나 잘 열렸음. 확인하려고 콜백 함수 작성하는 것. 콜백 없어도 돼!")})

 

 

 


npm init

  • npm init은 package.json 파일을 만들어준다.
    • package.json을 만들 때 속성을 입력하라고 한다.
  • package.json
    • npm을 통해 설치된 패키지 목록들을 관리하고 프로젝트의 정보 및 기타 실행 스크립트를 작성하는 파일이다.
    • 메타데이터 설명을 가지고 있는 json 파일. 초기화 명령어
      • 메타데이터: 데이터들을 설명해주는 데이터(속성)
        • 예) 책이 한 권 있다고 가정, 제목, 저자, 출판사 등의 책의 정보가 메타데이터.

 

npm init

  • 현재 디렉터리에 NPM 기반으로 프로젝트를 생성할 수 있다.
  • 패키지 이름, 버전, 설명 등의 정보들을 직접 입력해야 한다.
PS D:\Test> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help init` for definitive documentation on these fields
and exactly what they do.

Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
package name: (230501) test
version: (1.0.0) 1.0.0
description: test
git repository: test
author: test
license: (ISC) isc

...

 

npm init -y

  • 모든 설정을 기본 값으로 설정하는 명령어이다.
PS D:\Test> npm init -y
Wrote to D:\Test\package.json:
{
   "name": "230501",
   "version": "1.0.0",
   "main": "index.js",
   "scripts": {
      "test": "echo \"Error: no test specified\" && exit 1"
   },
   "keywords": [],
   "author": "",
   "license": "ISC",
   "dependencies": {
      "mysql2": "^3.2.4"
   },
   "devDependencies": {},
   "description": ""
}
  • name: 프로젝트의 이름이다.
  • version: 프로젝트의 버전을 정의한다.
  • description: 프로젝트의 설명. 문자열로 작성하면 된다.
  • keywords: 프로젝트를 검색할 때 참조하는 키워드들을 배열로 전달해주면 된다.
  • author: 패키지를 만든사람. 작업자 정보
  • license: 패키지 라이선스
  • main: 이 값을 작성해주면 패키지를 require 함수로 불러올 때 이 파일을 불러올 수 있다.
  • scripts: 우리가 자주 실행할 것 같은 명령어를 작성해두고 npm 명령어로 실행할 수 있다.
    • 예) npm run test
          "scripts" : {start : "node index4.js"} === npm start == node index4.js

 

 

 


외부 모듈 설치_Mysql2

Mysql2를 사용하는 이유

  • mysql 모듈도 있는데 왜 mysql2를 사용하는 것일까?
  • mysql 모듈은 콜백 기반이기 때문에 promise 기반으로 사용하기 힘들다.
  • mysql2는 promise 기반을 지원하기 때문에 사용하기 편하다.
  • 공식문서에서도 mysql2를 사용하라고 권장한다.

 

외부 모듈 설치받는 방법

  • npm 사이트에 접속하여 설치를 원하는 모듈을 검색한다.
  • 원하는 모듈을 선택해서 우측의 Install 코드를 복사한다.

  • 비주얼 스튜디오 코드로 돌아가 터미널에서 복사한 Install 코드를 붙여넣어 설치를 진행한다.

 

외부 모듈 설치 명령어

  • 모듈을 지정해서 설치하는 방법
// 둘 중 하나를 사용하면 된다.
npm install (외부 모듈의 이름)
npm i (외부 모듈의 이름)
  • package.json에 있는 dependencies 내용의 모듈을 다 설치받는 방법
    • 모듈을 사용한 작업물을 공유 시, 모듈도 같이 깃 등에 공유할 때는 포함시키지 않는다.
      • 모듈을 공유하는건 크기가 크고 시간이 오래걸리기 때문이다.
      • 때문에 다른 작업자들이 어떤 모듈을 설치했는지 알기도, 하나하나 찾아서 받기에도 쉽지 않으므로 한꺼번에 내려받는 방법이 편할 것이다.
// 둘 중 하나를 사용하면 된다.
npm install
npm i 

 

package.json에서 dependencies

//package.json
{
  "name": "230501",
  "version": "1.0.0",
	...
  "dependencies": {
    "mysql2": "^3.2.4"
  }
}
  • dependencies에서 ' ^3.2.4 '는 mysql2의 버전을 나타낸다. 그런데 버전 앞에 있는 ' ^ '는 무엇을 의미할까?
    • ^ : 해당 버전이 없으면 다른 버전을 찾아서 설치 받는다는 내용이다.
    • 실제 설치된 버전은 ' package-lock.json '에 있다.

 

 

 


Mysql 연결

Mysql Workbench_커넥션, 스키마 생성

  • 워크벤치에서 ' MySQL Connections ' 옆에 있는 ' + ' 버튼을 클릭하여 새로운 커넥션을 만든다.
    • 생성 시, 커넥션 이름/유저 이름/ 비밀번호 등의 설정을 확인하여 생성한다.

 

  • 해당 커넥션에 들어가 좌측 카테고리에서 ' Schemas ' 를 눌러 스키마 탭을 연다.
  • 스키마 생성: 스키마 탭에서 마우스 오른버튼을 클릭하여 'Create Schemas... '을 클릭한다.
    • Name : 원하는 이름을 작성한다.
    • Charset/Collation: 원하는 문자인코딩 방식과 정렬방식을 선택한다.
      • 현재는 Charset - utf8을, Collation -utf8_bin을 선택한다. 

 

Javascript_모듈 연결, Mysql 연결, 테이블 생성

  •  좌측 카테고리에서 스키마에 생성된 테이블을 찾는다. 
  • 테이블 이름 옆에 뜬 세 번째 아이콘을 선택한다.
  • Result Grid에서 null 값에 데이터를 입력한다.
    • 현재의 경우, id값은 고유한 값을 가지고 있고, 자동으로 값이 증가함으로 별도의 값을 입력하지 않아도 된다.

PS D:\Test> node index5.js
[
{ id: 1, name: '이름', number: '010-0000-0000', series: '123' },
{ id: 2, name: '내이름', number: '010-1111-1111', series: '456' },
{ id: 3, name: '네이름', number: '010-2222-2222', series: '789' }
]
테이블이 있어

 

 

 

 

 

 

728x90