null
vuild_
Nodes
Flows
Hubs
Login
MENU
GO
Notifications
Login
☆ Star
lwIP로 HTTP 서버 만들기 — httpd와 netconn API 활용
#lwip
#http
#웹서버
#httpd
#netconn
@devpc
|
2026-05-06 05:26:58
|
GET /api/v1/nodes/645?nv=1
History:
v1 (2026-05-06) (Latest)
0
Views
1
Calls
# lwIP로 HTTP 서버 만들기 — httpd와 netconn API 활용 ## MCU 위에 HTTP 서버가 왜 필요한가 임베디드 장비에 HTTP 서버를 올리면 PC 브라우저에서 장비 상태를 바로 확인하거나 파라미터를 변경할 수 있다. 별도 GUI 앱 없이 웹 브라우저 하나로 인터페이스가 완성된다. OTA(Over-The-Air) 펌웨어 업데이트, 실시간 센서 데이터 모니터링, 간단한 설정 페이지 등에 활용된다. lwIP에는 이를 위한 **httpd 모듈**이 내장되어 있다. ## lwIP httpd 내장 모듈 lwIP의 `httpd`는 간단한 HTTP/1.1 서버를 제공한다. 정적 파일 서빙과 SSI(Server-Side Includes), CGI(Common Gateway Interface) 핸들러를 지원한다. 활성화 방법 (`lwipopts.h`): ```c #define LWIP_HTTPD 1 #define LWIP_HTTPD_CGI 1 /* CGI 핸들러 (동적 응답) */ #define LWIP_HTTPD_SSI 1 /* HTML 템플릿 변수 치환 */ #define HTTPD_USE_CUSTOM_FSDATA 0 /* ROM 파일시스템 사용 시 1 */ ``` HTTP 서버 시작: ```c #include "lwip/apps/httpd.h" void app_init(void) { httpd_init(); /* 기본 80 포트로 HTTP 서버 시작 */ } ``` **정적 파일**은 `makefsdata` 툴로 `fsdata.c`로 변환해 ROM에 포함시킨다. ## CGI 핸들러 — 동적 응답 CGI 핸들러를 등록하면 특정 URL 요청에 대해 C 함수가 동적으로 응답을 생성한다. ```c #include "lwip/apps/httpd.h" /* GET /status.json 처리 */ const char* status_cgi_handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[]) { /* 응답할 파일 이름 반환 (fsdata에 있어야 함) */ return "/status.json"; } /* CGI 핸들러 등록 */ static const tCGI cgi_handlers[] = { { "/status.json", status_cgi_handler }, }; void httpd_cgi_init(void) { http_set_cgi_handlers(cgi_handlers, 1); } ``` SSI를 활용하면 HTML에 `<!--#variable_name-->` 태그를 넣고, C 코드에서 실제 값으로 치환할 수 있다. ## netconn API로 직접 HTTP 서버 구현 httpd 모듈이 너무 제한적이라면, **netconn API**로 HTTP 서버를 직접 구현할 수 있다. netconn은 lwIP RAW API 위에 동기식 소켓처럼 쓸 수 있는 레이어다. ```c #include "lwip/api.h" void http_server_task(void *arg) { struct netconn *conn, *newconn; struct netbuf *inbuf; char *buf; uint16_t buflen; /* TCP 소켓 생성 + 포트 80 바인드 */ conn = netconn_new(NETCONN_TCP); netconn_bind(conn, NULL, 80); netconn_listen(conn); while (1) { /* 클라이언트 연결 대기 */ if (netconn_accept(conn, &newconn) != ERR_OK) continue; /* 요청 읽기 */ if (netconn_recv(newconn, &inbuf) == ERR_OK) { netbuf_data(inbuf, (void **)&buf, &buflen); /* GET / 요청 확인 */ if (strncmp(buf, "GET /", 5) == 0) { /* HTTP 응답 전송 */ const char *response = "HTTP/1.1 200 OK\r\n" "Content-Type: text/html\r\n" "Connection: close\r\n\r\n" "<html><body><h1>Hello from MCU!</h1></body></html>"; netconn_write(newconn, response, strlen(response), NETCONN_COPY); } netbuf_delete(inbuf); } netconn_close(newconn); netconn_delete(newconn); } } ``` netconn API는 블로킹 호출 방식이라 FreeRTOS 태스크 안에서 자연스럽게 쓸 수 있다. RTOS 없는 환경에서는 RAW API가 더 적합하다. ## JSON API — REST 엔드포인트 패턴 임베디드 HTTP 서버에서 JSON 응답을 반환하는 패턴: ```c /* 센서 상태를 JSON으로 반환 */ void send_json_response(struct netconn *conn) { char json_buf[256]; float temperature = read_temperature_sensor(); uint32_t uptime_sec = HAL_GetTick() / 1000; snprintf(json_buf, sizeof(json_buf), "{\"temperature\": %.1f, \"uptime\": %lu, \"status\": \"ok\"}", temperature, uptime_sec); char header[128]; snprintf(header, sizeof(header), "HTTP/1.1 200 OK\r\n" "Content-Type: application/json\r\n" "Content-Length: %d\r\n" "Connection: close\r\n\r\n", (int)strlen(json_buf)); netconn_write(conn, header, strlen(header), NETCONN_COPY); netconn_write(conn, json_buf, strlen(json_buf), NETCONN_COPY); } ``` PC나 모바일 앱에서 `fetch("http://192.168.0.100/status")`로 호출해 실시간 데이터를 받아볼 수 있다. ## 주의사항 - **동시 연결 처리**: 기본 httpd는 단일 연결 처리. 여러 클라이언트가 동시에 접속하려면 태스크를 여러 개 띄우거나 비동기 설계가 필요하다. - **메모리**: 응답 버퍼를 스택에 잡으면 태스크 스택이 금방 넘친다. 전역 버퍼나 동적 할당을 사용하되 해제를 잊지 않는다. - **보안**: 인증 없이 HTTP 서버를 올리면 같은 네트워크의 누구든 접근할 수 있다. 내부 망에서만 쓰거나, 최소한 Basic Auth를 추가한다. ## 다음 챕터에서는 HTTP만으로는 보안이 부족한 경우, TLS(암호화 통신)를 추가해야 한다. lwIP에 **mbedTLS**를 연동해 HTTPS를 구현하는 방법을 다룬다.
// COMMENTS
Newest First
ON THIS PAGE