1. 투 포인터(Two Pointers) 알고리즘이란?

투 포인터는 두 개의 포인터를 이용하여 배열이나 리스트를 탐색하는 알고리즘 기법이다.
주로 정렬된 배열에서 특정 조건을 만족하는 쌍을 찾거나, 연속된 부분 배열을 탐색하는 문제에서 사용된다.

이 방법을 사용하면 O(N^2) 복잡도의 문제를 O(N)으로 최적화할 수 있습니다.


2. 투 포인터 동작 원리

  • 시작점과 끝점에서 이동
  • 오름차순 정렬된 배열에서 특정 합(target)을 찾을 때 사용
  • 좌측 포인터(left)는 작은 값부터, 우측 포인터(right)는 큰 값부터 이동
  • 두 포인터를 조절하면서 특정 조건을 만족하는 값을 찾는다.

아래 예제를 통해 원리에 대한 설명 하겠습니다.

 

특정 합을 가지는 두 숫자 찾기 (Two Sum)

문제: 정렬된 배열에서 합이 9 되는 두 숫자의 인덱스를 찾는다.

 

입력 예시

int[] nums = {1, 2, 3, 5, 7, 10, 12};
int target = 9;

 

투 포인터 진행 과정

1. left(🔴)는 처음 인덱스에서 시작, right(🔵)는 끝에서 시작

2. sum을 비교하면서 작으면 left++, 크면 right--

3. sum == target 이면 정답 찾음

단계 left 포인터 (🔴) right 포인터 (🔵) 합(sum) 진행 방향
초기 🔴1 (idx:0) 🔵12 (idx:6) 1 + 12 = 13 sum > target → right 감소
2 🔴1 (idx:0) 🔵10 (idx:5) 1 + 10 = 11 sum > target → right 감소
3 🔴1 (idx:0) 🔵7 (idx:4) 1 + 7 = 8 sum < target → left 증가
4 🔴2 (idx:1) 🔵7 (idx:4) 2 + 7 = 9 sum == target → 정답 찾음

 

최종결과 : [1, 4] → (nums[1] = 2, nums[4] = 7)

 

Java 코드

  • 시간 복잡도: O(N)
  • 두 개의 포인터를 사용하여 선형 탐색 진행
import java.util.Arrays;

public class MainClass {
	public static int[] twoSum(int[] nums, int target) {
        int left = 0, right = nums.length - 1;

        while (left < right) {
            int sum = nums[left] + nums[right];

            if (sum == target) {
                return new int[]{left, right}; // 정답
            } else if (sum < target) {
                left++; // 합이 작으면 왼쪽 포인터 증가
            } else {
                right--; // 합이 크면 오른쪽 포인터 감소
            }
        }
        return new int[]{-1, -1}; // 정답이 없을 경우
    }
	
	public static void main(String[] args) {
		int[] nums = {1, 2, 3, 5, 7, 10, 12};
		int target = 9;
        int[] result = twoSum(nums, target);
        
        // 최종결과: [1, 4]
        System.out.println("최종결과: " + Arrays.toString(result));
	}
}

3. 투 포인터 응용 예시

슬라이딩 윈도우를 활용한 부분 배열 최소 길이 찾기

문제 : 연속된 부분 배열의 합이 target 이상이 되는 최소 길이를 구하는 문제

          (left 포인터를 이동하며 구간을 줄여가면서 최적 해 찾기)

 

입력 예시

int[] nums = {2, 3, 1, 2, 4, 3};
int target = 7;

 

포인터 이동 과정

단계 left(🔴) right(🔵) 부분합(sum) 최소 길이
초기 🔴2 (idx:0) 🔵2 (idx:0) sum = 2 -
2 🔴2 (idx:0) 🔵3 (idx:1) sum = 5 -
3 🔴2 (idx:0) 🔵1 (idx:2) sum = 6 -
4 🔴2 (idx:0) 🔵2 (idx:3) sum = 8 minLength = 4
5 🔴3 (idx:1) 🔵2 (idx:3) sum = 6 -
6 🔴3 (idx:1) 🔵4 (idx:4) sum = 10 minLength = 3
7 🔴1 (idx:2) 🔵4 (idx:4) sum = 7 minLength = 3
8 🔴2 (idx:3) 🔵4 (idx:4) sum = 6 -
9 🔴2 (idx:3) 🔵3 (idx:5) sum = 9 minLength = 2

 

최소 길이 부분 배열: [4, 3] (길이: 2)

Java코드

  • 시간 복잡도: O(N)
  • 슬라이딩 윈도우(Sliding Window) 방식으로 최적화
  • 연속된 부분 배열을 유지하면서 최소 길이 갱신
public class MainClass {
	public static int minSubArrayLen(int target, int[] nums) {
        int left = 0, sum = 0, minLength = Integer.MAX_VALUE;

        for (int right = 0; right < nums.length; right++) {
            sum += nums[right]; // 오른쪽 포인터 확장

            while (sum >= target) { // 조건을 만족하면 최소 길이 업데이트
                minLength = Math.min(minLength, right - left + 1);
                sum -= nums[left]; // 왼쪽 포인터 축소
                left++;
            }
        }

        return (minLength == Integer.MAX_VALUE) ? 0 : minLength;
    }

    public static void main(String[] args) {
        int[] nums = {2, 3, 1, 2, 4, 3};
        int target = 7;
        int result = minSubArrayLen(target, nums);

        System.out.println("최소 길이: " + result); // 최소 길이: 2 (부분 배열: [4,3])
    }
}

4. 투 포인터 알고리즘이 적합한 문제 유형

1) 정렬된 배열에서 특정 조건을 만족하는 두 수 찾기

  • Two Sum 문제 (합, 차이)
  • 배열에서 두 숫자의 차이가 K인 쌍 찾기
  • 배열에서 곱이 특정 값을 만족하는 두 수 찾기

2) 연속된 부분 배열 문제

  • 최소 길이의 부분 배열 찾기
  • 가장 큰 합을 가지는 연속된 부분 배열 찾기

3) 문자열 처리 문제

  • 가장 긴 중복 없는 부분 문자열 찾기
  • 애너그램(Anagram) 검사

4) 백준 및 프로그래머스 관련 문제

  • 백준 - 3273번: 두 수의 합, 2470번: 두 용액, 1806번: 부분합, 1644번: 소수의 연속합, 2003번: 수들의 합 2
  • 프로그래머스 - 레벨 2: 구명보트, 레벨 3: 보석 쇼핑, 레벨 2: 연속된 부분 수열의 합

5. 정리

투 포인터 알고리즘은 정렬된 배열에서 최적의 방법으로 특정 조건을 만족하는 요소를 찾는 강력한 알고리즘 입니다.

  • 브루트포스 대비 O(N²) → O(N)으로 성능 최적화 가능
  • 슬라이딩 윈도우와 결합하여 다양한 문제 해결 가능
  • 데이터 크기가 클수록 효과적인 알고리즘

위와같은 장점도 있지만, 투포인터 알고리즘은 중복된 값이 있는 경우 차가적인 고려가 필요합니다. 또한 배열이나 리스트에서는 효과적이지만 트리, 그래프, 해시맵과 같은 비선형 자료구조에서는 적용 하기 어렵다는 단점이 있습니다.

 

1. Chunked Transfer Encoding이란?

Chunked Transfer Encoding은 HTTP/1.1에서 도입된 데이터 전송 방식으로, 데이터를 고정된 크기가 아닌, 여러 개의 작은 청크(Chunk)로 나누어 전송하는 방식이다. 이 방식은 서버가 모든 데이터를 한 번에 생성하지 않아도, 데이터가 준비되는 대로 클라이언트에게 스트리밍 방식으로 전송할 수 있도록 해주고, Content-Length를 명시하지 않고도 데이터를 스트리밍 방식으로 전송할 수 있도록 해줍니다. 즉, 응답 본문의 크기를 미리 알 수 없을 때 유용하게 사용됩니다.


2. Chunked Transfer Encoding의 장점과 단점

장점

Chunked Transfer Encoding(청크 전송 인코딩)은 HTTP/1.1에서 응답 크기를 미리 알 수 없을 때, 데이터를 조각(chunk) 단위로 전송하는 방식입니다. 이 방식은 여러 상황에서 유용한 이점을 제공합니다.

1) 응답 크기를 미리 알 필요 없음

  - Content-Length를 사용할 경우, 서버는 응답의 크기를 미리 계산해야 함.

  - 하지만, Chunked Transfer Encoding은 데이터가 생성되는 대로 전송 가능하므로 응답 크기를 사전에 알 필요가 없음.

  - 예시 상황

  • 실시간 로그 스트리밍
  • 동적 콘텐츠 생성 (대량 데이터 처리)
  • 점진적 웹 페이지 렌더링 (Server-Sent Events)

2) 빠른 응답 가능 (Low Latency)

  - Chunked Transfer Encoding을 사용하면 서버가 모든 데이터를 준비하지 않아도 즉시 응답을 시작할 수 있음.

  - 데이터를 점진적으로 전송하여 클라이언트가 일부 데이터를 먼저 처리할 수 있도록 함.

  - 특히 느린 데이터베이스 쿼리 또는 API 요청이 포함된 응답에서 효과적.

3) 실시간 데이터 전송 및 스트리밍 지원

  - Chunked Transfer Encoding을 사용하면 스트리밍 데이터(예: 로그, 실시간 API, 비디오 등)를 지속적으로 전송 가능.

  - 예시 상황

  • 실시간 로그 전송
  • WebSocket 대체용 Server-Sent Events (SSE)
  • 대량 데이터 처리 API (예: AI 모델 예측 결과 점진적 제공)

4) 서버 리소스 절약

  - Content-Length 방식은 응답 데이터를 모두 준비한 후 전송하므로 서버의 메모리를 많이 사용할 수 있음.

  - 반면, Chunked Transfer Encoding은 데이터를 작은 조각으로 나누어 바로 전송하므로, 메모리 사용량을 줄일 수 있음.

  - 서버가 한 번에 모든 데이터를 메모리에 로드하지 않아도 되므로, RAM 사용량이 줄고, 효율적인 자원 관리가 가능.

5) 클라이언트가 부분적으로 데이터를 사용할 수 있음

  - 일반적인 HTTP 응답(Content-Length)은 데이터를 모두 수신한 후에야 사용할 수 있음.

  - 하지만 Chunked Transfer Encoding을 사용하면, 클라이언트가 데이터를 순차적으로 받아 바로 사용할 수 있음.

  - 예시 상황

  • 프론트엔드에서 데이터 점진적 렌더링 (예: 페이지 로딩 속도 향상)
  • 비동기 요청 처리 (대용량 데이터 API에서 JSON 데이터 일부만 먼저 처리)

6) HTTP Keep-Alive와 함께 사용 가능

  - Chunked Transfer Encoding은 HTTP/1.1의 Keep-Alive 연결과 함께 사용 가능.

  - 한 번의 연결을 유지하면서 여러 개의 청크를 지속적으로 전송 가능 → 연결을 여러 번 맺을 필요 없이 성능 향상.

  - 예시 상황

  • 실시간 금융 데이터 피드
  • IoT 센서 데이터 스트리밍
  • 대량 파일 업로드 후 처리 상태 전송

단점

Chunked Transfer Encoding(청크 전송 인코딩)은 동적 데이터를 스트리밍 방식으로 전송하는 데 유용하지만, 몇 가지 단점이 있습니다.

 

1) 클라이언트에서 청크 데이터 처리 필요

  - 일반적인 HTTP 응답과 달리, 클라이언트는 청크 크기를 해석하고 데이터를 조립해야 함.

  - 일부 단순한 클라이언트(옛날 웹 브라우저, 특정 IoT 장치 등)는 Transfer-Encoding: chunked를 제대로 지원하지

    않을 수 있음.

  - 예시 문제: 청크 응답을 처리할 수 없는 클라이언트가 데이터를 제대로 렌더링하지 못할 수 있음.

  - 해결 방법: 최신 브라우저 및 HTTP 라이브러리를 사용하고, API 응답을 JSON으로 변환하여 관리.

 

2) 추가적인 네트워크 및 성능 오버헤드

  - 각 청크마다 크기 정보(16진수)와 개행 문자(\r\n)가 포함되므로, 데이터 크기가 약간 증가할 수 있음.

  - HTTP 헤더와 비교하면 큰 차이는 없지만, 고빈도 요청이 발생하는 경우 네트워크 대역폭을 조금 더 소비할 수 있음.

  - 해결 방법:

  • 작은 청크 전송을 최소화하고, 가능한 경우 일정 크기의 청크로 묶어서 전송.
  • JSON, 압축(Gzip) 등을 활용하여 전송 데이터 크기를 최적화.

3) HTTP/2 및 HTTP/3에서는 불필요

  - HTTP/2 및 HTTP/3는 멀티플렉싱과 스트리밍이 기본적으로 지원되므로 Chunked Transfer Encoding이 필요 없음.

  - HTTP/1.1에서는 유용하지만, 최신 프로토콜에서는 효율성이 떨어짐.

  - 해결 방법: 가능하면 HTTP/2 이상을 사용하여 더 효율적인 데이터 전송 구현.

 

4) 중간 프록시/캐시 서버와의 비호환성

  - 일부 프록시 서버(Nginx, Cloudflare, Squid 등)는 Chunked Transfer Encoding을 지원하지 않거나 제한할 수 있음.

  - 캐시 서버는 전체 응답 크기를 알아야 하기 때문에 청크 데이터는 캐싱하기 어려움.

  - 해결 방법:

  • 프록시 또는 로드 밸런서를 사용한다면 Chunked Encoding 지원 여부 확인.
  • 캐싱이 필요한 경우 Content-Length 방식으로 전송.

5) 서버에서 청크 전송 도중 연결이 끊길 경우, 클라이언트에서 응답을 제대로 처리하지 못할 수 있음

  - 청크 전송 도중 네트워크 오류가 발생하면, 클라이언트는 불완전한 데이터를 수신할 수 있음.

  - 일반 HTTP 응답(Content-Length 포함)에서는 클라이언트가 전체 데이터를 받을 때까지 기다릴 수 있지만,

    청크 응답에서는 데이터 일부가 누락될 가능성이 있음.

  - 해결 방법:

  • 클라이언트 측에서 타임아웃 및 오류 핸들링 로직 추가.
  • 서버에서는 적절한 연결 유지 정책 및 재시도(retry) 로직 구현.

6) 데이터 압축(Gzip, Brotli)과 함께 사용하기 어려움

  - Chunked Transfer Encoding과 Content-Encoding: gzip을 함께 사용할 경우, 일부 서버 및 클라이언트에서

    정상적으로 해석되지 않는 문제가 발생할 수 있음.

  - 이유: 압축 데이터는 완전한 데이터 세트가 있어야 해석 가능하지만, 청크 방식은 데이터가 나눠져 있기 때문에

    압축된 청크가 올바르게 해석되지 않을 수 있음.

  - 해결 방법:

  • 압축이 필요한 경우 Content-Length를 사용하는 일반 HTTP 응답 방식으로 전송.
  • 서버에서 미리 압축된 데이터를 생성한 후 전송.

3. Chunked Transfer Encoding의 동작 방식

서버가 클라이언트에 응답을 줄 때 데이터를 작은 블록 단위로 보낸다면 다음과 같은 HTTP 응답을 보낼 수 있습니다.

여기서 각 청크(Chunk)는 데이터의 크기와 내용을 순차적으로 전송 합니다.

 

- Content-Length 헤더 없이 데이터를 여러 개의 "청크(chunk)"로 나누어 전송
- 각 청크 앞에는 해당 청크의 크기를 16진수로 표시
- 마지막 청크 크기는 0으로 전송하며, 이는 응답의 끝을 의미

 

HTTP 응답 (Chunked Encoding 적용)

형식

[청크 크기(16진수)]\r\n
[청크 데이터]\r\n
...
0\r\n
\r\n

 

각 청크는 크기(16진수) + 데이터로 이루어지고, 마지막 청크는 크기 `0`을 전송하여 전송 완료를 알림.

 

예제

Content-Length 사용 (정적 데이터)

HTTP/1.1 200 OK
Content-Length: 20
Content-Type: text/plain

Hello, this is text.

Content-Length는 HTTP 응답 본문의 크기(바이트 단위)를 나타냅니다.

 

Chunked Transfer Encoding 사용 (동적 데이터)

HTTP/1.1 200 OK
Transfer-Encoding: chunked
Content-Type: text/plain

5\r\n
Hello\r\n
7\r\n
, World!\r\n
0\r\n
\r\n

 

"Hello,World!"가 조각(Chunk)으로 나누어 전송되고, 해당 응답을 분석하면 아래와 같이 데이터를 응답하게 된다.

 

  • 5 → 첫 번째 청크 크기 (16진수, 5 = 10진수로 5 바이트)
  • Hello → 첫 번째 청크 데이터
  • 7 → 두 번째 청크 크기 (16진수, 7 = 10진수로 7 바이트)
  • , World! → 두 번째 청크 데이터
  • 0 → 마지막 청크 (전송 종료 의미)

 

정적 vs 동적 데이터 전송 비교

구분 정적 데이터 전송 동적 데이터 전송
데이터 특성 고정된 크기의 데이터 실시간 생성되는 데이터
Content-Length 사용 여부 보통 Content-Length 사용 (일부 경우 Chunked) Content-Length 없이 Chunked 사용
응답 흐름 한 번에 응답 전송 데이터가 생성될 때마다 전송
예제 HTML, CSS, JSON 파일 다운로드 실시간 로그, 스트리밍 API 응답
전송 방식 데이터 전체 준비 후 전송 데이터가 준비될 때마다 조각으로 전송

4. 정리

Chunked Transfer Encoding은 실시간 데이터 전송, 빠른 응답, 서버 리소스 절약, 로그 전송, 대량 데이터 처리 등의 장점이 있어 API, 스트리밍, 대규모 데이터 처리 등에 적합하다. 하지만 네트워크 오버헤드, 캐시 문제, HTTP/2 미지원 등의 한계가 있으므로 상황에 맞게 사용해야 한다고 생각 한다.

'기타 > CS' 카테고리의 다른 글

[HTTP] HyperText Transfer Protocol  (0) 2025.03.02

1. HTTP란?

HTTP (HyperText Transfer Protocol)

HTTP는 웹에서 클라이언트(브라우저)와 서버 간 데이터를 주고받는 프로토콜입니다.  
웹 페이지, API 요청, 파일 다운로드 등의 모든 웹 통신에서 사용됩니다.

 

HTTP 특징

  • 비연결성 (Stateless) : 한 번의 요청-응답 후 연결이 종료됨.
  • 무상태성 (Stateless) : 각각의 요청은 독립적이며, 이전 요청 정보를 기억하지 않음.
  • TCP/IP 기반 : HTTP는 기본적으로 TCP(전송 제어 프로토콜)를 사용하여 데이터 전송.
  • 주요 버전 :
- HTTP/1.1: 기본적인 웹 통신 방식.
- HTTP/2: 멀티플렉싱 지원(여러 요청 동시 처리), 헤더 압축.
- HTTP/3: QUIC 기반으로 더 빠른 데이터 전송.

2. HTTP 요청 (HTTP Request)

클라이언트(브라우저 또는 API 클라이언트)가 서버에 정보를 요청하는 방식입니다.

 

HTTP 요청의 기본 구조

GET /index.html HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0
Accept: text/html

 

구성 요소

1) 요청 라인 (Request Line)

  • HTTP 메서드 : GET, POST, PUT, DELETE, PATCH 등.
  • URL (경로, 리소스 위치) : /index.html
  • HTTP 버전 : HTTP/1.1

2) 헤더 (Headers)

요청에 대한 추가 정보를 전달.

예시:

  • Host : 요청을 보내는 서버 도메인 (http://www.example.com)
  • User-Agent : 클라이언트(브라우저, 앱)의 정보 (Mozilla/5.0)
  • Accept : 응답에서 원하는 데이터 형식 (text/html)

3) 바디 (Body, 선택적)

  • POST, PUT 요청에서 데이터를 전송할 때 사용.
  • JSON, XML, Form 데이터 등을 포함할 수 있음.

주요 HTTP 요청 메서드

메서드 설명
GET 리소스를 조회 (데이터 가져오기)
POST 새로운 리소스를 생성 (데이터 전송)
PUT 기존 리소스를 수정 (전체 변경)
PATCH 기존 리소스를 부분 수정 (일부 변경)
DELETE 리소스를 삭제

3. HTTP 응답 (HTTP Response)

서버가 클라이언트의 요청에 대해 반환하는 응답입니다.

 

HTTP 응답 구조

HTTP/1.1 200 OK
Date: Sun, 02 Mar 2025 12:00:00 GMT
Server: Apache/2.4.41 (Ubuntu)
Content-Type: text/html
Content-Length: 1256

<html>
  <body>Hello, World!</body>
</html>

 

구성 요소

1) 상태 라인 (Status Line)

  • HTTP 버전 : HTTP/1.1
  • 상태 코드(Status Code) : 200
  • 상태 메시지(Status Message) : OK

2) 헤더 (Headers)

  • Date : 응답 시간 (Sun, 02 Mar 2025 12:00:00 GMT)
  • Server : 서버 정보 (Apache/2.4.41 (Ubuntu))
  • Content-Type : 응답 데이터 유형 (text/html)
  • Content-Length : 응답 데이터의 크기 (1256 바이트)

3) 바디 (Body)

  • 클라이언트가 요청한 데이터 (HTML, JSON 등)

HTTP 응답 상태 코드

상태코드 의미
200 OK 요청 성공
201 Created 새로운 리소스 생성
204 No Content 요청 성공, 내용 없음
301 Moved Permanently 리소스 영구 이동
302 Found 리소스 임시 이동
400 Bad Request 잘못된 요청
401 Unauthorized 인증 필요
403 Forbidden 접근 금지
404 Not Found 요청한 리소스를 찾을 수 없음
500 Internal Server Error 서버 내부 오류
502 Bad Gateway 게이트웨이 오류
503 Service Unavailable 서버 과부하 또는 점검 중

4. 정리

  • HTTP (HyperText Transfer Protocol)은 웹에서 클라이언트와 서버 간 데이터를 주고받는 프로토콜이다.
  • 요청(Request)은 GET, POST, PUT, DELETE 등의 메서드를 사용하여 서버에 데이터를 요청한다.
  • 응답(Response)은 상태 코드(200 OK, 404 Not Found 등)와 함께 요청된 데이터를 반환한다.
  • HTTP는 기본적으로 Stateless(무상태성)을 가지며, 이를 보완하기 위해 쿠키, 세션, 토큰 등이 사용된다.

'기타 > CS' 카테고리의 다른 글

[HTTP] Chunked Transfer Encoding  (0) 2025.03.02

 

C++ 에서 Javascript 함수를 호출하고, 반대로 Javascript에서 C++ 함수를 호출하는 예제를 포스팅 해보겠습니다. Webassembly로 컴파일 하기위해서는 C++작성된 디렉토리로 이동 후에 아래와 같이 명령어를 실행 하면 아래와 같이 wasm 파일을 생성 할 수 있습니다, (※ Webassembly 환경 세팅 및 자세한 컴파일 방법은 이전 포스팅 참고)

## WebAssembly 컴파일
emcc -lembind -o [생성 할  파일명] [변환할 파일명]

## WebAssembly 컴파일 예시
emcc -lembind -o call_analysis.js call_analysis.cpp

 


Javascript to C++ 함수 호출하기

 

C++에서 선언된 my_analysis 함수를 Javascript에서 사용 하기 위해서 

"EMSCRIPTEN_BINDINGS안에 emscripten::function("javascript에서 호출 할 함수명", C++에서 선언된 함수 반환값)"

와 같이 함수 인자를 입력하여 매핑 작업 한 후 호출하여 사용합니다.

아래 예제 소스를 기준으로 설명하면, 소스에서 emscripten::function("analysis", &my_analysis)와 같이 매핑 후에

javascript에서 analysis함수 호출시 C++의 my_analysis 함수로 반환 시켜 C++에서 선언된 함수를 호출 할 수 있습니다.

C++ 소스
#include <emscripten/bind.h>
using namespace emscripten;

float my_analysis(float a, float b, float c)
{
	return a + b * c;
}

EMSCRIPTEN_BINDINGS(my_module)
{
	emscripten::function("analysis", &my_analysis);
}
Javascript 소스
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script>
        var Module = {
            onRuntimeInitialized: function() {
                reqForm.arg1.value = 1.5;
                reqForm.arg2.value = 3.5;
                reqForm.arg3.value = 0.5;
            }
        };

        function getResult() {
            let arg1 = parseFloat(reqForm.arg1.value);
            let arg2 = parseFloat(reqForm.arg2.value);
            let arg3 = parseFloat(reqForm.arg3.value);

            let myRet = Module.analysis(arg1, arg2, arg3);
            reqForm.result.value = myRet;
        }
    </script>
    <script src="call_analysis.js"></script>
</head>
<body>
    <form method="get" id="reqForm" onsubmit="return false;">
        <input type="text" name="arg1" value="" size="3"> +
        <input type="text" name="arg2" value="" size="3"> X
        <input type="text" name="arg3" value="" size="3"> =
        <input type="text" name="result" value="" size="3">
        <input type="button" onClick="getResult()" value="결과 얻어오기">
    </form>
</body>
</html>

C++ to Javascript 함수 호출하기

 

C++에서 Javascript 함수를 호출 하기 위해서는 EM_JS를 통하여 호출 가능합니다. 아래 예제와 같이 javascript에서 선언된 함수 jsFunction와 같이 EM_JS에서도 인자값과 인코딩 타입을 맞춰준 후에 호출하여 사용하면 됩니다.

C++ 소스
#include <iostream>
#include <string>

#include <emscripten.h>
#include <emscripten/bind.h>

EM_JS(void, call_js,(const char *subject, int len_subject, const char *msg, int len_msg), {
	jsFunction(UTF8ToString(subject, len_subject),UTF8ToString(msg, len_msg));
});

bool my_callJs()
{
	const std::string subject= "하이하이";
	const std::string msg = "나를 호출해줘~";
	
	call_js(subject.c_str(), subject.length(), msg.c_str(), msg.length());
	
	return true;
}

EMSCRIPTEN_BINDINGS(module)
{
	emscripten::function("callJs", &my_callJs);
}

 

Javascript 소스
<!DOCTYPE html>
<html lang="kr">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>CALL_JSFUNC</title>
    <script>
        var Module = {
            onRuntimeInitialized: () => {
                Module.callJs();
            }
        }

        const jsFunction = (subject, msg) => {
            document.querySelector('#my_div').innerText = subject;
            document.querySelector('#my_title').innerText = msg;
        }
    </script>
    <script src="call_jsfunc.js"></script>
</head>
<body>
    [ 제 목 ]
    <div id="my_div"></div>

    [ 내 용 ]
    <div id="my_title"></div>
</body>
</html> 

 

이번 포스팅은 WebAssembly에서 C++ to Javascript(Javascript to C) 함수 호출하는 방법을 정리 해봤습니다. 여기까지 지루한 글 읽어주셔서 감사합니다.

1. C언어 Source File 작성

 

Emscripten을 사용하여 WebAssembly 아래와 같이 간단한 C언어로 예제 소스를 만들어 줍니다.

Visual Studio Code, Visual Studio 2022 등 편하신 환경에서 상관 없지만, Embarcadero Dev-C++ 환경에서 구구단을 출력해주는 프로그램을 작성 하였습니다. 작성 완료 하면 다음으로 WebAssembly 컴파일을 진행 하겠습니다.

/**
File Name : multiple.c
**/
#include <stdio.h>

void multiple(int grades)
{
	for(int i = 1; i <= 9; i++)
	{
		printf("%d * %d = %d\n", grades, i, grades*i);
	}
}

int main()
{
	multiple(2);
	
	return 0;
}

 

2. Emscripten 사용하여 WebAssembly 컴파일
Emscripten 명령어

WebAssembly 컴파일(wasm 파일 생성)을 위해서는 C언어로 작성된 코드파일이 있는 디렉토리로 이동하여, 아래와 같이 명령어를 입력해 줍니다. 컴파일에 성공하면 html, js, wasm 3가지 파일이 생성됩니다.

# WebAssembly 컴파일 명령어(wasm파일 생성)
emcc [input파일명] -s WASM=1 -o [output파일명]

#실제 명령어
emcc multiple.c -s WASM=1 -o multiple.html

컴파일 성공 결과

 

다음으로 wasm 파일을 실행하기 위해서 컴파일 결과물이 있는 경로에서 python web server를 사용하여 컴파일 결과물을 실행 할 수 있습니다. 꼭 python web server가 아니더라도 apach, xampp, nginx 등 다른 서버를 사용하여 실행해도 무관합니다. 웹서버 실행에 성공하면 http://localhost:8080/multiple.html 주소로 접속하면 결과물을 확인 할 수 있습니다.

#Python 웹서버 실행
python -m http.server [포트번호]

#예시
python -m http.server 8080

파이썬 웹서버 실행 결과
wasm 파일 실행 결과

 

이번 포스팅에서는 C언어로 작성된 간단한 프로그램 소스코드를 사용해  WebAssembly 컴파일을 진행해 봤습니다. 다음 포스팅은 이어서 C언어에서 Javascript, Javascript에서 C언어로 함수를 호출하는 예제를 포스팅 해보겠습니다. 여기까지 지루한 글 읽어주셔서 감사합니다 ㅎㅎ

에러 발생 상화

(1) use로 Database 변경하였을때.

mysql> use kdhong_db

[MySql] ERROR 1044 (42000): Access denied for user 'user'@'localhost' to database 'userdb'

 

(2) MySQL의 ROOT계정(관리자계정)으로 아이디 생성 후 로그인 하였을때.

mysql> mysql -ulucky -p1234 lucky_db

[MySql] ERROR 1044 (42000): Access denied for user 'lucky'@'localhost' to database 'lucky_db'

 

※로그인 하는 방법 :> mysql -u아이디 -p비밀번호 데이터베이스명

 

해결방법

$ mysql -uroot -p1234

 

mysql> grant all privileges on userdb.* to 'lucky'@'localhost' identified by '패스워드' with grant option;

Query OK, 0 rows affected (0.16 sec)

mysql> flush privileges;

Query OK, 0 rows affected (0.11 sec)

+ Recent posts