7주차_IP와 포트 포워딩_웹 서버(2) - sookite22/SmartDivice_24 GitHub Wiki
- 서버 동작 방식
- 동기 방식
- 비동기 방식
- IP 주소란?
- IP 주소
- 포트(Port)란?
- 포트 포워딩(Port Forwarding)
- 실습
- LED 제어 웹 서버
- DH11 온습도 제어하기
- 후기
- 크게 동기 방식과 비동기 방식으로 나뉜다.
동기 방식에서는 작업이 순차적으로 수행된다. 한 작업이 완료된 후에야 다음 작업이 시작한다.
- 작업 대기: 서버가 클라이언트의 요청을 받으면 해당 요청을 처리하는 동안 다른 요청을 처리하지 않고 기다린다.
- 직관적 흐름: 코드의 실행 흐름이 순처적으로 진행되므로 직관적이다.
- 성능 문제: 여러 요청이 동시에 들어오면 대기 시간이 증가하고, 서버의 응답 시간이 느려질 수가 있다. 하나의 요청이 오래 걸리면 다른 요청들도 모두 영향을 받는다.
작업이 동시에 수행된다. 한 작업의 완료를 기다리지 않고, 다른 작업을 동시에 처리할 수 있다.
- 작업 병렬 처리: 서버가 클라이언트의 요청을 받으면 해당 요청을 비동기적으로 처리하고 다른 요청도 동시에 처리한다.
- 효율적인 자원 사용: 서버의 자원을 더 효율적으로 사용할 수 있다. 특히 I/O 작업(파일 읽기/쓰기, 네트워크 통신 등)에서 큰 장점을 가진다. 대기 시간이 감소하고, 더 많은 요청을 처리할 수 있다.
- 복잡한 코드 흐름: 코드의 실행 흐름이 복잡하다.
컴퓨터 네트워크에서 장치를 식별하기 위해 사용되는 고유한 주소 이다. 모든 네트워크 장치에는 고유한 IP 주소가 할당되며, 이를 통해 다른 장치와 통신하거나 어떠한 컴퓨터를 특정할 수 있다.
IP 주소는 일반적으로 32비트(IPv4)로 표현된다. IPv4 주소는 네 개의 8비트 숫자로 나뉘어져 있으며, 각 숫자는 0부터 255까지의 값으로 표현된다. 예를 들어, "192.0.2.1"과 같은 형식이다.
- 공인 IP: 인터넷 상에서 고유하며, 전 세계적으로 라우팅되며 인터넷에 접속 가능하다.
- 사설 IP: 사설 네트워크 내에서 사용된다. 인터넷에서 직접 액세스할 수 없으며 주로 가정이나 기업 내부의 네트워크에서 사용된다.
예를 들어, '공유기' 라고 하는 기계를 들여 하나의 통신사 회선에 정액제 방식으로 연결한다. 공유기와 각각의 컴퓨터와 연결하면 하나의 통신사 회선으로 여러 대의 컴퓨터를 사용할 수 있다. 케이블로 직접 연결하기 어려운 노트북이나 스마트폰 이용 시 무선으로 공유기와 통신이 가능한데 이것을 Wi-Fi 라고 한다. 이때, 공유기와 연결되어있는 기기은 각자의 IP 주소 를 가지며, 공유기는 공인 IP, 연결되어있는 기기들은 사설 IP이다.
공인 IP는 전 세계에서 고유한 IP를 가져야 하지만, 사설 IP는 공유기의 네트워크 안에서만 유일하면 되기에 효율적인 접속이 가능하다.
포트는 통신을 할 때 이용되는 출입구 라고 생각하면 된다. 네트워크 통신에서 각 프로세스나 서비스는 고유한 포트 번호를 할당받아 그 포트를 통해 통신한다. 이렇게 포트를 사용하여 네트워크 상에서 다른 장치나 서버와 데이터를 주고받을 수 있다.
HTTP 웹 서버는 보통 80번 포트를 사용하는데, 이러한 잘 알려진 포트는 네트워크 상에서 특정 서비스를 식별하기 위해 사용된다. IP 주소와 함께 사용되어 데이터를 송수신하고, 네트워크 통신의 원활한 진행을 보장한다.
인터넷을 통해 내부 네트워크에 있는 장치에 외부에서 접속할 수 있도록 하는 네트워크 설정이다. 일반적으로, 내부 네트워크에 있는 장치들은 사설 IP 주소를 사용하여 서로 통신하며, 외부에서는 직접 이러한 장치에 접속할 수 없다. 포트 포워딩을 사용하면 외부에서 특정 포트로 들어오는 요청을 내부 네트워크의 특정 장치로 전달할 수 있게 된다.
- 위 사진은 iptime 포트 포워딩 예시이다.
포트 포워딩을 설정하는 방법은 라우터(공유기도 가능하다)나 방화벽의 관리자 설정 페이지 에서 수행된다. 대개 포트 포워딩은 외부 포트와 내부 포트, 그리고 내부 네트워크에 있는 장치의 사설 IP 주소를 지정하여 설정한다. 설정을 마쳤다면, 외부에서 해당 포트로 요청이 들어오면 라우터 는 이를 내부 네트워크의 특정 장치로 전달하게 된다.
포트 포워딩은 서버를 호스팅하거나 특정 서비스를 제공하는 경우에 유용하며, 원격 접속이 필요한 경우에도 활용될 수 있습니다. 그러나 보안상 주의해야 하며, 필요한 경우에만 필요한 포트에 대한 포트 포워딩을 설정하는 것이 좋다.
- 라이브러리 매니저에서 'ESPAsyncWebSrv' 를 검색하고 설치한다.
- 위 코드는 HTML, CSS, 람다 함수 등 불필요한 요소가 많아 어려울 수 있다. 아래 코드는 간단하게 '웹 브라우저를 통해 각 경로로 접속하여 GPIO 핀의 상태를 제어할 수 있으며, 웹 페이지는 이 상태 변경을 반영하여 text/plain 사용자에게 표시해주는 코드'이다.
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
const char* ssid = ""; // WiFi 네트워크 이름
const char* password = ""; // WiFi 비밀번호
String output2State = "off"; // GPIO 핀의 초기 상태
const int output2 = 2; // GPIO 핀 번호
AsyncWebServer server(80); // 서버 포트 설정
void setup() {
Serial.begin(115200);
pinMode(output2, OUTPUT); // GPIO 핀을 출력으로 설정
digitalWrite(output2, LOW); // 초기 상태를 LOW로 설정
// WiFi에 연결
WiFi.begin(ssid, password);
Serial.print("WiFi 연결 중");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.print("연결된 WiFi 네트워크: ");
Serial.println(WiFi.SSID());
Serial.print("IP 주소: ");
Serial.println(WiFi.localIP());
// 루트 경로 설정
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) {
String message = "GPIO 2 현재 상태: " + output2State;
request->send(200, "text/plain; charset=utf-8", message); // Content-Type에 charset=utf-8 추가
});
// GPIO 핀 ON 설정 경로
server.on("/2/on", HTTP_GET, [] (AsyncWebServerRequest *request) {
Serial.println("GPIO 2 ON");
output2State = "on";
digitalWrite(output2, HIGH);
String message = "GPIO 2 변경됨: ON";
request->send(200, "text/plain; charset=utf-8", message); // Content-Type에 charset=utf-8 추가
});
// GPIO 핀 OFF 설정 경로
server.on("/2/off", HTTP_GET, [] (AsyncWebServerRequest *request) {
Serial.println("GPIO 2 OFF");
output2State = "off";
digitalWrite(output2, LOW);
String message = "GPIO 2 변경됨: OFF";
request->send(200, "text/plain; charset=utf-8", message); // Content-Type에 charset=utf-8 추가
});
server.begin(); // 웹 서버 시작
}
void loop() {
// 메인 코드에 특별한 실행 로직이 없는 경우 loop()는 비워둘 수 있습니다.
}
- 아래 코드처럼 람다 함수를 사용하지 않고 실행할 수도 있다.
아래 코드는 동일한 내용을 람다함수를 사용하지 않고 작성한 버전
#include <WiFi.h>
#include <ESPAsyncWebServer.h>
#include <AsyncTCP.h>
const char* ssid = "yourSSID"; // WiFi 네트워크 이름
const char* password = "yourPassword"; // WiFi 비밀번호
String output2State = "off"; // GPIO 핀의 초기 상태
const int output2 = 2; // GPIO 핀 번호
AsyncWebServer server(80); // 서버 포트 설정
void handleRoot(AsyncWebServerRequest *request) {
String message = "GPIO 2 현재 상태: " + output2State;
request->send(200, "text/plain", message);
}
void handleGpioOn(AsyncWebServerRequest *request) {
Serial.println("GPIO 2 ON");
output2State = "on";
digitalWrite(output2, HIGH);
String message = "GPIO 2 변경됨: ON";
request->send(200, "text/plain", message);
}
void handleGpioOff(AsyncWebServerRequest *request) {
Serial.println("GPIO 2 OFF");
output2State = "off";
digitalWrite(output2, LOW);
String message = "GPIO 2 변경됨: OFF";
request->send(200, "text/plain", message);
}
void setup() {
Serial.begin(115200);
pinMode(output2, OUTPUT);
digitalWrite(output2, LOW);
// WiFi에 연결
WiFi.begin(ssid, password);
Serial.print("WiFi 연결 중");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("연결된 WiFi 네트워크: " + String(ssid));
Serial.println("IP 주소: " + WiFi.localIP().toString());
// 루트 경로 설정
server.on("/", HTTP_GET, handleRoot);
// GPIO 핀 ON 설정 경로
server.on("/2/on", HTTP_GET, handleGpioOn);
// GPIO 핀 OFF 설정 경로
server.on("/2/off", HTTP_GET, handleGpioOff);
server.begin(); // 웹 서버 시작
}
void loop() {
// 메인 코드에 특별한 실행 로직이 없는 경우 loop()는 비워둘 수 있습니다.
}
ESP32의 주소를 확인하고 브라우저에 입력한다.
- 'ON' 버튼을 클릭하면 ESP32에 LED가 점등되는 것을 확인할 수 있다.
DH11 센서: 온도와 상대 습도를 측정하기 위해 사용되는 저렴한 디지털 센서이다.
라이브러리 매니저에서 'DHT sensor library by Adafruit' 를 설치한다. 연관된 'Adafruit Unified Sensor' 라이브러리도 모두 설치해야 한다.
- 시리얼 모니터를 통해 실시간으로 온습도 결과를 확인한다. 체온 혹은 입김 등으로 온습도 변화를 확인할 수 있다.
IP 주소의 할당 원리에 대해 더 자세히 살펴볼 수 있었다. 가정에서 흔히 사용하는 공유기를 예를 들어 기존에 알던 IP에 대한 지식의 틀을 쉽고 간단하게 구조화할 수 있었던 유익한 시간이었다. IP 주소는 인터넷의 보급화로 인해 부족해졌지만 사설 IP와 공인 IP 등을 구분하여 효율적으로 할당 가능하도록 구현한 것이 현재 인터넷 발전에도 크게 기여할 수 있었다. 이 밖에도 주소 변환 기술인 NAT 등의 고갈된 IP를 위한 기술들을 찾아보게 된 계기가 되었다. 또, HTML과 CSS 등의 다른 언어와 접목한 코드를 실행해보며 코드 작성에 대한 창의성을 향상시킬 수 있었다.