본문 바로가기

ESP32

ESP32 클라이언트-서버 Wi-Fi 통신(두 보드 간)

반응형

 

 

ESP32 클라이언트-서버 Wi-Fi 통신(두 보드 간)

 

이 가이드에서는 인터넷 연결(라우터) 없이 Wi-Fi를 통해 데이터를 교환하기 위해 두 ESP32 보드 간에 HTTP 통신을 설정하는 방법을 보여줍니다. 간단히 말해서 HTTP 요청을 사용하여 한 보드에서 다른 보드로 데이터를 보내는 방법을 배우게 됩니다. ESP32 보드는 Arduino IDE를 사용하여 프로그래밍됩니다.

 

ESP32 클라이언트-서버 Wi-Fi 통신(두 보드 간)

 

데모 목적으로 BME280 센서 판독값을 한 보드에서 다른 보드로 보냅니다. 수신기는 OLED 디스플레이에 판독값을 표시합니다.

 

ESP8266 보드가 있는 경우 이 전용 가이드를 읽을 수 있습니다. ESP8266 NodeMCU 클라이언트-서버 Wi-Fi 통신.

 

비디오 데모 보기

 

프로젝트가 어떻게 작동하는지 보려면 다음 비디오 데모를 시청할 수 있습니다.

 

프로젝트 개요

 

한 ESP32 보드는 서버 역할을 하고 다른 ESP32 보드는 클라이언트 역할을 합니다. 다음 다이어그램은 모든 것이 작동하는 방식을 간략하게 보여줍니다.

 

ESP32 클라이언트-서버 간 Wi-Fi 통신 프로젝트 개요

 

 

  • ESP32 서버는 자체 무선 네트워크(ESP32 소프트 액세스 포인트)를 만듭니다. 따라서 다른 Wi-Fi 기기가 해당 네트워크에 연결할 수 있습니다(SSID: ESP32-Access-Point, 비밀번호: 123456789).
  • ESP32 클라이언트는 스테이션으로 설정됩니다. 따라서 ESP32 서버 무선 네트워크에 연결할 수 있습니다.
  • 클라이언트는 서버에 HTTP GET 요청을 보내 센서 데이터나 다른 정보를 요청할 수 있습니다. 특정 경로(/temperature, /humidity 또는 /pressure)에서 요청을 하려면 서버의 IP 주소만 사용하면 됩니다.
  • 서버는 들어오는 요청을 수신하고 판독값과 함께 적절한 응답을 보냅니다.
  • 클라이언트는 판독값을 수신하여 OLED 디스플레이에 표시합니다.

 

예를 들어 ESP32 클라이언트는 서버 IP 주소에 요청을 보낸 다음 각각 /temperature, /humidity 및 /pressure를 보내 서버에 온도, 습도 및 압력을 요청합니다.

 

ESP32 서버는 해당 경로를 수신하고 요청이 발생하면 HTTP 응답을 통해 해당 센서 판독값을 보냅니다.

 

필요한 부품

 

ESP32 클라이언트-서버 통신에 필요한 부품

 

이 튜토리얼에서는 다음 부품이 필요합니다.

 

  • 2x ESP32 개발 보드 - 최고의 ESP32 보드 리뷰 읽기
  • BME280 센서
  • I2C SSD1306 OLED 디스플레이
  • 점퍼 와이어
  • 브레이보드

라이브러리 설치: 이 튜토리얼에서는 다음 라이브러리를 설치해야 합니다.

 

비동기 웹 서버 라이브러리

 

다음 라이브러리를 사용하여 HTTP 요청을 처리합니다.

 

 

 

 

https://github.com/dvarrel/AsyncTCP

 

 

 

이러한 라이브러리는 라이브러리 관리자를 통해 설치할 수 없습니다. 따라서 라이브러리를 압축 해제하여 Arduino IDE 설치 라이브러리 폴더로 옮겨야 합니다.

 

또는 Sketch > Include Library > Add .ZIP library…로 이동하여 방금 다운로드한 라이브러리를 선택할 수 있습니다.

 

다음도 마음에 드실 수 있습니다: ESP32로 비동기 웹 서버 구축

 

BME280 라이브러리

 

다음 라이브러리는 Arduino 라이브러리 관리자를 통해 설치할 수 있습니다. Sketch > Include Library > Manage Libraries로 이동하여 라이브러리 이름을 검색합니다.

 

  • Adafruit_BME280 라이브러리
  • Adafruit unified sensor 라이브러리

다음도 마음에 드실 수 있습니다: ESP32로 BME280 인터페이스(가이드)

 

I2C SSD1306 OLED 라이브러리

 

OLED 디스플레이와 인터페이스하려면 다음 라이브러리가 필요합니다. Arduino 라이브러리 관리자를 통해 설치할 수 있습니다. Sketch > Include Library > Manage Libraries로 이동하여 라이브러리 이름을 검색합니다.

 

  • Adafruit SSD1306
  • Adafruit GFX 라이브러리

다음도 마음에 드실 수 있습니다: ESP32가 있는 I2C SSD1306 OLED 디스플레이(가이드)

 

#1 ESP32 서버(액세스 포인트)

 

BME280 온도 습도 압력이 있는 ESP32 서버

 

ESP32 서버는 /temperature, /humidity 및 /pressure URL에서 요청을 수신하는 액세스 포인트(AP)입니다. 해당 URL에서 요청을 받으면 최신 BME280 센서 판독값을 보냅니다.

 

데모 목적으로 BME280 센서를 사용하지만 몇 줄의 코드를 수정하면 다른 센서를 사용할 수 있습니다.

 

회로도

 

다음 회로도에 표시된 대로 ESP32를 BME280 센서에 연결합니다.

 

ESP32 BME280 배선도

 

 

BME280 ESP32
VIN/VCC 3.3V
GND GND
SCL GPIO 22
SDA GPIO 21

 

#1 ESP32 서버에 대한 Arduino 스케치

 

다음 코드를 보드에 업로드합니다.

 

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-client-server-wi-fi/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

// Import required libraries
#include "WiFi.h"
#include "ESPAsyncWebServer.h"

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

// Set your access point network credentials
const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

/*#include <SPI.h>
#define BME_SCK 18
#define BME_MISO 19
#define BME_MOSI 23
#define BME_CS 5*/

Adafruit_BME280 bme; // I2C
//Adafruit_BME280 bme(BME_CS); // hardware SPI
//Adafruit_BME280 bme(BME_CS, BME_MOSI, BME_MISO, BME_SCK); // software SPI

// Create AsyncWebServer object on port 80
AsyncWebServer server(80);

String readTemp() {
  return String(bme.readTemperature());
  //return String(1.8 * bme.readTemperature() + 32);
}

String readHumi() {
  return String(bme.readHumidity());
}

String readPres() {
  return String(bme.readPressure() / 100.0F);
}

void setup(){
  // Serial port for debugging purposes
  Serial.begin(115200);
  Serial.println();
  
  // Setting the ESP as an access point
  Serial.print("Setting AP (Access Point)…");
  // Remove the password parameter, if you want the AP (Access Point) to be open
  WiFi.softAP(ssid, password);

  IPAddress IP = WiFi.softAPIP();
  Serial.print("AP IP address: ");
  Serial.println(IP);

  server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readTemp().c_str());
  });
  server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readHumi().c_str());
  });
  server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
    request->send_P(200, "text/plain", readPres().c_str());
  });
  
  bool status;

  // default settings
  // (you can also pass in a Wire library object like &Wire2)
  status = bme.begin(0x76);  
  if (!status) {
    Serial.println("Could not find a valid BME280 sensor, check wiring!");
    while (1);
  }
  
  // Start server
  server.begin();
}
 
void loop(){
  
}

 

코드 작동 방식

 

필요한 라이브러리를 포함하는 것으로 시작합니다. WiFi.h 라이브러리와 ESPAsyncWebServer.h 라이브러리를 포함하여 들어오는 HTTP 요청을 처리합니다.

 

#include "WiFi.h"

#include "ESPAsyncWebServer.h"

 

다음 라이브러리를 포함하여 BME280 센서와 인터페이스합니다.

 

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>

 

 

다음 변수에서 액세스 포인트 네트워크 자격 증명을 정의합니다.

 

const char* ssid = "ESP32-Access-Point";

const char* password = "123456789";

 

SSID를 ESP32-Access-Point로 설정하지만 다른 이름을 지정할 수 있습니다. 비밀번호도 변경할 수 있습니다. 기본적으로 123456789로 설정됩니다.

 

bme라는 BME280 센서의 인스턴스를 만듭니다.

 

Adafruit_BME280 bme;

 

포트 80에서 비동기 웹 서버를 만듭니다.

 

AsyncWebServer server(80);

 

그런 다음 온도, 습도 및 압력을 문자열 변수로 반환하는 세 개의 함수를 만듭니다.

 

String readTemp() {
  return String(bme.readTemperature());
  //return String(1.8 * bme.readTemperature() + 32);
}

String readHumi() {
  return String(bme.readHumidity());
}

String readPres() {
  return String(bme.readPressure() / 100.0F);
}

 

setup()에서 데모 목적으로 직렬 모니터를 초기화합니다.

 

Serial.begin(115200);

 

ESP32를 이전에 정의한 SSID 이름과 비밀번호로 액세스 포인트로 설정합니다.

 

WiFi.softAP(ssid, password);

 

그런 다음 ESP32가 들어오는 요청을 수신할 경로를 처리합니다.

 

예를 들어 ESP32 서버가 /temperature URL에서 요청을 받으면 readTemp() 함수에서 반환된 온도를 char로 전송합니다(이것이 c_str() 메서드를 사용하는 이유입니다.

 

server.on("/temperature", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readTemp().c_str());
});

 

ESP가 /humidity 및 /pressure URL에서 요청을 받을 때도 마찬가지입니다.

 

server.on("/humidity", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readHumi().c_str());
});
server.on("/pressure", HTTP_GET, [](AsyncWebServerRequest *request){
  request->send_P(200, "text/plain", readPres().c_str());
});

 

다음 줄은 BME280 센서를 초기화합니다.

 

bool status;

// 기본 설정 
// (&Wire2와 같은 Wire 라이브러리 객체를 전달할 수도 있음) 
status = bme.begin(0x76); 
if (!status) 
{ 
	Serial.println("유효한 BME280 센서를 찾을 수 없습니다. 배선을 확인하세요!"); 
    while (1); 
}

 

마지막으로 서버를 시작합니다.

 

server.begin();

 

비동기 웹 서버이므로 loop()에 아무것도 없습니다.

 

void loop(){

}

 

ESP32 서버 테스트

 

보드에 코드를 업로드하고 직렬 모니터를 엽니다. 다음과 같은 결과가 나와야 합니다. 아래와 같은 메시지가 나오지 않으면 보드의 RESET 버튼을 눌렀다 뗍니다.

 

ESP32 서버 직렬 모니터 Arduino IDE 테스트

 

이것은 액세스 포인트가 성공적으로 설정되었음을 의미합니다.

 

이제 온도, 습도 및 압력 요청을 수신하는지 확인하려면 네트워크에 연결해야 합니다.

 

스마트폰에서 Wi-Fi 설정으로 이동하여 ESP32-Access-Point에 연결합니다. 비밀번호는 123456789입니다.

 

ESP32 서버 액세스 포인트 AP 연결

 

액세스 포인트에 연결된 상태에서 브라우저를 열고 192.168.4.1/temperature를 입력합니다.

 

브라우저에서 온도 값을 가져와야 합니다.

 

ESP32 서버 액세스 포인트 AP 테스트 요청 온도

 

습도 192.168.4.1/humidity에 대한 이 URL 경로를 시도합니다.

 

ESP32 서버 액세스 포인트 AP 테스트 요청 습도

 

마지막으로 192.168.4.1/pressure URL로 이동합니다.

 

 

ESP32 서버 액세스 포인트 AP 테스트 요청 압력 유효한 판독값을 얻고 있다면 모든 것이 제대로 작동하고 있다는 의미입니다. 이제 다른 ESP32 보드(클라이언트)를 준비하여 해당 요청을 하고 OLED 디스플레이에 표시해야 합니다.

 

#2 ESP32 클라이언트(스테이션)

 

ESP32 클라이언트가 HTTP GET 요청을 통해 판독값을 수신 BME280

 

ESP32 클라이언트는 ESP32 서버에 연결된 Wi-Fi 스테이션입니다. 클라이언트는 /temperature, /humidity, /pressure URL 경로에서 HTTP GET 요청을 하여 서버에 온도, 습도, 압력을 요청합니다. 그런 다음 OLED 디스플레이에 판독값을 표시합니다.

 

회로도: 다음 회로도에 표시된 대로 ESP32를 OLED 디스플레이에 연결합니다.

 

 

 

OLED ESP32
VIN/VCC VIN
GND GND
SCL GPIO 22
SDA GPIO 21

 

 

#2 ESP32 클라이언트를 위한 Arduino 스케치

 

다음 코드를 다른 ESP32에 업로드합니다.

 

/*
  Rui Santos
  Complete project details at https://RandomNerdTutorials.com/esp32-client-server-wi-fi/
  
  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files.
  
  The above copyright notice and this permission notice shall be included in all
  copies or substantial portions of the Software.
*/

#include <WiFi.h>
#include <HTTPClient.h>

const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

//Your IP address or domain name with URL path
const char* serverNameTemp = "http://192.168.4.1/temperature";
const char* serverNameHumi = "http://192.168.4.1/humidity";
const char* serverNamePres = "http://192.168.4.1/pressure";

#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     4 // Reset pin # (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

String temperature;
String humidity;
String pressure;

unsigned long previousMillis = 0;
const long interval = 5000; 

void setup() {
  Serial.begin(115200);
  
  // Address 0x3C for 128x64, you might need to change this value (use an I2C scanner)
  if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextColor(WHITE);
  
  WiFi.begin(ssid, password);
  Serial.println("Connecting");
  while(WiFi.status() != WL_CONNECTED) { 
    delay(500);
    Serial.print(".");
  }
  Serial.println("");
  Serial.print("Connected to WiFi network with IP Address: ");
  Serial.println(WiFi.localIP());
}

void loop() {
  unsigned long currentMillis = millis();
  
  if(currentMillis - previousMillis >= interval) {
     // Check WiFi connection status
    if(WiFi.status()== WL_CONNECTED ){ 
      temperature = httpGETRequest(serverNameTemp);
      humidity = httpGETRequest(serverNameHumi);
      pressure = httpGETRequest(serverNamePres);
      Serial.println("Temperature: " + temperature + " *C - Humidity: " + humidity + " % - Pressure: " + pressure + " hPa");
      
      display.clearDisplay();
      
      // display temperature
      display.setTextSize(2);
      display.setTextColor(WHITE);
      display.setCursor(0,0);
      display.print("T: ");
      display.print(temperature);
      display.print(" ");
      display.setTextSize(1);
      display.cp437(true);
      display.write(248);
      display.setTextSize(2);
      display.print("C");
      
      // display humidity
      display.setTextSize(2);
      display.setCursor(0, 25);
      display.print("H: ");
      display.print(humidity);
      display.print(" %"); 
      
      // display pressure
      display.setTextSize(2);
      display.setCursor(0, 50);
      display.print("P:");
      display.print(pressure);
      display.setTextSize(1);
      display.setCursor(110, 56);
      display.print("hPa");
           
      display.display();
      
      // save the last HTTP GET Request
      previousMillis = currentMillis;
    }
    else {
      Serial.println("WiFi Disconnected");
    }
  }
}

String httpGETRequest(const char* serverName) {
  WiFiClient client;
  HTTPClient http;
    
  // Your Domain name with URL path or IP address with path
  http.begin(client, serverName);
  
  // Send HTTP POST request
  int httpResponseCode = http.GET();
  
  String payload = "--"; 
  
  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  // Free resources
  http.end();

  return payload;
}

 

코드 작동 방식

 

Wi-Fi 연결과 HTTP 요청을 위한 필수 라이브러리를 포함합니다.

 

#include <WiFi.h>
#include <HTTPClient.h>

 

 

ESP32 서버 네트워크 자격 증명을 삽입합니다. ESP32 서버에서 기본 네트워크 자격 증명을 변경한 경우 여기에서 변경하여 일치시켜야 합니다.

 

const char* ssid = "ESP32-Access-Point";
const char* password = "123456789";

 

그런 다음 클라이언트가 HTTP 요청을 할 URL을 저장합니다. ESP32 서버의 IP 주소는 192.168.4.1이고, /temperature, /humidity, /pressure URL에 대한 요청을 할 것입니다.

 

const char* serverNameTemp = "http://192.168.4.1/temperature";
const char* serverNameHumi = "http://192.168.4.1/humidity";
const char* serverNamePres = "http://192.168.4.1/pressure";

 

OLED 디스플레이와 인터페이스하기 위한 라이브러리를 포함합니다.

 

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

 

OLED 디스플레이 크기를 설정합니다.

 

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

 

이전에 정의한 크기와 I2C 통신 프로토콜을 사용하여 디스플레이 객체를 만듭니다.

 

Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

 

서버에서 검색한 온도, 습도 및 압력 판독값을 보관할 문자열 변수를 초기화합니다.

 

String temperature;
String humidity;
String pressure;

 

각 요청 간의 시간 간격을 설정합니다. 기본적으로 5초로 설정되지만 다른 간격으로 변경할 수 있습니다.

 

const long interval = 5000;

 

setup()에서 OLED 디스플레이를 초기화합니다.

 

// 128x64의 경우 주소 0x3C, 이 값을 변경해야 할 수도 있습니다(I2C 스캐너 사용)

 

// Address 0x3C for 128x64, you might need to change this value (use an I2C scanner)
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
  Serial.println(F("SSD1306 allocation failed"));
  for(;;); // Don't proceed, loop forever
}
display.clearDisplay();
display.setTextColor(WHITE);

 

참고: OLED 디스플레이가 작동하지 않으면 I2C 스캐너 스케치를 사용하여 I2C 주소를 확인하고 코드를 적절히 변경합니다.

 

ESP32 클라이언트를 ESP32 서버 네트워크에 연결합니다.

 

WiFi.begin(ssid, password);
Serial.println("Connecting");
while(WiFi.status() != WL_CONNECTED) { 
  delay(500);
  Serial.print(".");
}
Serial.println("");
Serial.print("Connected to WiFi network with IP Address: ");

 

loop()에서 HTTP GET 요청을 합니다. 요청을 만들려는 URL 경로를 인수로 받아들이고 응답을 문자열로 반환하는 httpGETRequest()라는 함수를 만들었습니다.

 

다음 함수를 프로젝트에서 사용하여 코드를 간소화할 수 있습니다.

 

String httpGETRequest(const char* serverName) {
  HTTPClient http;
    
  // Your IP address with path or Domain name with URL path 
  http.begin(serverName);
  
  // Send HTTP POST request
  int httpResponseCode = http.GET();
  
  String payload = "--"; 
  
  if (httpResponseCode>0) {
    Serial.print("HTTP Response code: ");
    Serial.println(httpResponseCode);
    payload = http.getString();
  }
  else {
    Serial.print("Error code: ");
    Serial.println(httpResponseCode);
  }
  // Free resources
  http.end();

  return payload;
}

 

이 함수를 사용하여 서버에서 온도, 습도 및 기압 판독값을 가져옵니다.

 

temperature = httpGETRequest(serverNameTemp);
humidity = httpGETRequest(serverNameHumi);
pressure = httpGETRequest(serverNamePres);

 

디버깅을 위해 해당 판독값을 직렬 모니터에 인쇄합니다.

 

Serial.println("Temperature: " + temperature + " *C - Humidity: " + humid + " % - Pressure: " + pressure + " hPa");

 

그런 다음 OLED 디스플레이에 온도를 표시합니다.

 

display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
display.print("T: ");
display.print(temperature);
display.print(" ");
display.setTextSize(1);
display.cp437(true);
display.write(248);
display.setTextSize(2);
display.print("C");

 

 

습도

 

display.setTextSize(2);
display.setCursor(0, 25);
display.print("H: ");
display.print(humidity);
display.print(" %");

 

 

마지막으로 압력 읽기

 

display.setTextSize(2);
display.setCursor(0, 50);
display.print("P:");
display.print(pressure);
display.setTextSize(1);
display.setCursor(110, 56);
display.print("hPa");

display.display();

 

지연 대신 타이머를 사용하여 x초마다 요청을 합니다. 그래서 previousMillis, currentMillis 변수가 있고, millis() 함수를 사용합니다. 타이머와 지연의 차이점을 보여주는 기사가 있는데, 유용할 수 있습니다(또는 ESP32 타이머를 읽어보세요).

 

#2 ESP32(클라이언트)에 스케치를 업로드하여 모든 것이 제대로 작동하는지 테스트합니다.

 

ESP32 클라이언트 테스트

 

두 보드를 비교적 가까이 두고 전원을 공급하면 ESP #2가 ESP #1에서 5초마다 새로운 온도, 습도 및 압력 판독값을 수신하는 것을 볼 수 있습니다.

 

ESP32 클라이언트 직렬 모니터에서 볼 수 있는 내용입니다.

 

ESP32 클라이언트 직렬 모니터 Arduino IDE 테스트

 

센서 판독값도 OLED에 표시됩니다.

 

ESP32 클라이언트 서버 통신 예제 센서 재지정을 위한 데이터 교환

 

두 보드가 서로 통신하고 있습니다.

 

ESP32에서 ESP32로 무선 통신으로 서로 통신

 

마무리

 

이 튜토리얼에서는 인터넷에 연결할 필요 없이 HTTP 요청을 사용하여 Wi-Fi를 통해 한 ESP32에서 다른 ESP32 보드로 데이터를 보내는 방법을 알아보았습니다. 데모 목적으로 BME280 센서 판독값을 보내는 방법을 보여드렸지만 다른 센서를 사용하거나 다른 데이터를 보낼 수 있습니다. 권장하는 다른 센서:

 

ESP32 DHT11 또는 DHT22(가이드)

ESP32 DS18B20(가이드)

DHT11 대 DHT22 대 DS18B20 대 BME280

 

유용할 만한 ESP8266에 대한 유사한 튜토리얼이 있습니다.

 

ESP8266 NodeMCU 두 보드 간의 클라이언트-서버 Wi-Fi 통신

 

이 튜토리얼이 유용했기를 바랍니다. 이와 같은 튜토리얼을 더 많이 준비하고 있습니다. 계속 지켜봐 주시고 블로그를 구독해 주세요!

 

긴 시간 고생 많으셨습니다.

 

읽어주셔서 감사합니다. 배움을 멈추지 마세요. 인생의 여정을 즐기세요.

 

반응형

더욱 좋은 정보를 제공하겠습니다.~ ^^