티스토리 뷰

이번 글은 안드로이드 부스트코스 마지막 네트워킹 강의의 내용을 정리해 보려고 한다. 이 강의는 실습이 아닌 네트워킹의 전반적인 내용을 2시간 동안 개괄적으로 훑는 강의였기 때문에 그에 맞게 내가 이해한 이론적인 내용을 주로 다룰 것이다.

 

 

강의의 개요는 아래와 같이 세 가지로 구성된다.

 

1. 일반 데이터 네트워킹

  • 대부분의 업무용 앱과 일반 앱 중 서버와의 통신이 필요한 앱에 적용하는 일반적인 네트워킹 방법
  • Thread, AsyncTask, Gson 정리 및 Node.js를 이용한 클라우드 서버 구성 방법에 대한 요약

2. 실시간 메시징

  • 카톡 등 실시간 메시징이 필요한 경우에 적용하는 네트워킹 방법
  • Socket.IO 정리 및 Node.js를 이용한 클라우드 서버 구성 방법에 대한 요약

3. 실시간 방송

  • 동영상 시청 및 실시간 방송 제공 및 시청이 필요한 경우에 적용하는 방법
  • YouTube API를 이용한 구성 방법에 대해 요약

 

 

네트워크 모델은 Client-Server 모델을 기본적으로 하고, 3-tier C/S 모델(클라이언트 <-> 애플리케이션 서버 <-> 데이터 서버)과 서버 부하를 줄이기 위한 P2P(Pear-To-Pear) 모델이 있다. P2P 모델은 서버 없이 클라이언트끼리 통신하는 순수 P2P 모델과 클라이언트를 찾아서 연결해주는 가장 단순한 역할만 하는 서버가 존재하는 하이브리드 P2P 모델로 구분할 수 있다.

 


 

일반 데이터 네트워킹

[소켓 사용하기]

네트워크 통신의 가장 기초는 소켓(Socket)이다. 소켓은 TCP 레벨에서 작동하기 때문에 먼저 클라이언트와 서버를 연결한 뒤 데이터를 송수신하며 통신을 한다. 여기서 소켓을 이용해 만든 서버를 소켓 서버라고 하는데, 강의에서 소켓 서버는 Java로 만들었지만 일반적으로 Node.js를 이용해 서버를 만든다. 이 때 net 패키지를 이용한다.

 

 

Node.js란 웹 기반 라이브러리가 잘 만들어져 있어 웹 서버를 만드는 데 일반적으로 사용 되는 플랫폼이다. javascript 언어를 사용하는데, Java나 Spring보다 훨씬 단순하게 서버를 만들 수 있다는 장점이 있다. (php와 성격이 비슷하다.) 또한 비동기 처리 프로그래밍으로 서버 성능이 좋다.

 

 

소켓 클라이언트는 PC나 모바일 애플리케이션 등이 될 수 있는데, 통신을 위해 소켓을 사용해 서버와 연결한 뒤 데이터를 송수신하며 서버와 통신한다.

 

1. 소켓 연결

public void createSocket() throws Exception {
    socket = new Socket(hostname, port);
    instream = new DataInputStream(socket.getInputStream()); 
    outstream = new DataOutputStream(socket.getOutputStream());
}
  • 서버가 Java로 만들어진 경우 ObjectInputStream/ObjectOutputStream을 사용할 수 있지만, 서버가 C나 Node.js로 만들어진 경우 Object 개념이 없기 때문에 Object 단위로 통신을 할 수가 없다. 그렇기 때문에 byte array로 통신을 하는 DataInputStream/DataOutputStream을 사용해야 한다.

2. 데이터 송신

public void send(String data) throws Exception {
    byte[] outBytes = data.getBytes(“UTF8”);
    outstream.write(outBytes);
    outstream.flush();
    Log.d(TAG, "서버로 보냄 : " + data);
}

 

3. 데이터 수신

public String receive() {
    byte[] inBytes = new byte[1024];
    
    int count = instream.read(inBytes, 0, inBytes.length);
    return new String(inBytes, 0, count, “UTF8”);
}

 

안드로이드에서 소켓 클라이언트를 구현할 때 주의할 점이 있다. permission에 INTERNET 권한을 추가해야 한다는 점과, 네트워킹 동작을 무조건 다른 Thread를 별도로 사용해야 하기 때문에 응답을 받아서 UI를 변경해 줘야 할 경우 handler를 통해 UI thread에게 UI 변경 요청을 해야한다는 점이다. UI thread가 아닌 다른 thread에서 UI 변경 작업을 하면 에러가 발생한다. 이는 UI가 threads 간 공통 리소스이기 때문에 race condition이 발생할 수 있고, 이를 막기 위해 안드로이드에서 main thread를 UI thread로 지정한 뒤 UI thread에서만 UI 변경을 허용하도록 했기 때문이다.

 

 

 

그렇다면 실무에서 소켓 사용 시 발생하는 일반적인 이슈는 뭐가 있을까.

 

먼저 소켓 서버를 모바일 단말에 올릴 수 있을까에 대한 의문이다. 

소켓 서버는 반드시 PC, IDC, Cloud에 있는 서버에만 올려서 실행시켜야만 할까? 그렇지 않다. 소켓 서버를 모바일 단말에 올려 실행할 수 있고, 다른 모바일 단말에서 클라이언트로 접속할 수 있다. 이 경우에 단말 간의 통신이 된다. 

하지만 단말 간 통신의 경우 다음과 같은 문제점이 있다.

  1. 같은 네트워크 망 안에 있어야 통신이 가능하다.

    서로 다른 망에 있을 때에 통신하고 싶다면 그 망을 뚫고 통신을 해야 하고, 망에 방화벽이 있다면 그 방화벽도 뚫고 들어가야 한다. 이 때 STUN, TURN, ICE 등의 프로토콜을 이용하는데, 이 기능의 동작에 대해 오픈되어 있지 않기 때문에 동작을 이해하는 데는 상당히 많은 시간이 필요하다. 하지만 사용하기 위한 오픈 소스는 존재하기 때문에 개발을 할 때는 오픈소스를 가져다 쓰면 된다.

  2. Server Discovery

    서버 소켓이 모바일 단말에 들어가 있다면 그 단말이 서버라는걸 누군가가 알려줘야 한다. 그래서 단말에서는 서버를 실행하면 자신이 서버라는 것을 어딘가에 올리고 다른 클라이언트가 그 서버를 찾아서 접속하는 방법을 사용하고 이를 Server Discovery라고 한다.

 

두 번째로는 여러 클라이언트를 동시에 처리하는 방법이다.

서버에서 여러 클라이언트의 요청이 들어왔을 때 얼마나 빨리 응답을 주느냐가 서버 성능을 결정한다. 

  1. 일반적으로는 클라이언트 요청마다 스레드를 할당해서 처리하는 방법을 사용한다.

    프로그램 성능 저하 방지를 위해 스레드 풀(thread pool)에서 스레드를 할당 받아서 클라이언트 요청을 수행하고 작업이 끝나면 그 다음 클라이언트 요청을 받아서 작업한다. 만약 클라이언트 요청이 들어왔는데 모든 스레드가 작업 중이면 그 요청은 작업을 마친 스레드가 생길 때 까지 대기해야 한다.

    하지만 이렇게 스레드를 직접 다루는 작업은 신경 쓸 작업이 많아지고 코드의 복잡도도 증가하기 때문에 요즘엔 거의 사용 되지 않는 방법이다.

  2. 기본적으로 비동기로 진행하는 기술을 사용한다.

    Java의 NIO, Netty 또는 RxJava와 Node.js 등 비동기(이벤트) 프로그래밍을 지원하는 많은 기술들이 나왔고, 이를 사용하면 직접 스레드를 신경 쓸 필요 없이 자동으로 비동기적으로 클라이언트 요청을 처리하기 때문에 서버 성능이 좋아진다.

    요즘엔 성능이 점점 좋은 방식으로 만들어진 iOS의 swift 언어가 나왔는데, 이를 Server-side에서 사용하게 되면 성능을 많이 개선할 수 있다. (아직 일반화 되지 않아 일부만 사용 중이다.)

 

 

참고로 안드로이드 클라이언트에서 동기 처리와 비동기 처리의 차이점은 다음과 같다.

동기(synchronous) 처리는 요청을 보내고 응답 올 때까지 blocking되어 기다린 뒤 응답이 오면 그 다음 요청을 보내는 방식이고, 

비동기(asynchronous) 처리는 요청을 보내고 다른 작업을 진행하다가 응답이 오면 응답에 대한 처리를 진행하는 방식으로, 요청을 여러개 보냈다면 응답이 올 때까지 다른 작업을 진행하다가 응답이 오면 응답 온 순서대로 처리한다. 안드로이드 클라이언트에서 비동기 처리를 위해 Message Queue와 Handler의 개념을 이해해야 한다. 또한 비동기 방식을 사용할 때 AsyncTask를 사용하면 데이터를 주고 받는 동작을 하나의 task로 묶어서 별도의 코드에서 처리할 수 있다. 이 개념은 [부스트코스 PJ5 정리노트] 스레드와 핸들러에서 자세히 다룬 적 있다.

 

 

 

 

[웹 사용하기]

웹 성능이 좋아지면서 소켓을 통한 네트워킹은 거의 없고 웹을 이용한 통신이 일반화가 되었다. 그 이유는 웹을 사용하는 방법이 소켓보다 쉽기 때문이다. 웹은 소켓을 기반으로 하는 통신으로, 소켓과 마찬가지로 데이터를 주고 받을 수 있지만 그 데이터가 일반 문자열이 아닌 Http 형식의 데이터라는 점이 다르다. 웹을 이용해 통신을 하게 되면 클라이언트가 웹 브라우저가 될 수 있다. 

웹 서버가 소켓을 기반으로 한다는 것은 소켓 서버에서 응답 데이터를 보낼 때 Http 형식으로 보내면 웹 클라이언트가 응답 데이터에 대한 처리를 할 수 있다는 것이다.

 

웹 클라이언트는 Http 형식의 데이터를 처리해야 하기 때문에 기본적으로 헤더를 이해하고 조작할 수 있어야 한다. 하지만 안드로이드에서는 헤더를 이해하지 않아도 Http 형식의 데이터를 쉽게 조작할 수 있도록 라이브러리를 지원해 준다. 대표적인 라이브러리가 HttpUrlConnection이고, 이 라이브러리에서 소켓을 연결하고 끊는 당의 작업도 알아서 수행해 주기 때문에 사용하면 코드 양도 줄어들고 시간도 단축되어 아주 편리하다. (하지만 보안 관련 작업을 할 때에는 헤더를 이해하고 직접 조작하는 것이 중요하기 때문에 라이브러리를 사용하지 않는 것이 좋다.) 많은 웹 통신 라이브러리가 있지만, 그 라이브러리들의 기반이 HttpUrlConnection이기 때문에 HttpUrlConnection 라이브러리는 직접 사용해 보고 이해하는 것을 권장한다.

 

 

실무에서 웹 통신을 할 때 발생하는 문제는 다음과 같다.

 

1. 코드의 단순화가 필요하다.

  • 스레드, 핸들러, HttpUrlConnection 기본 코드 등 boilerplate 코드가 많아 코드 양이 증가한다.

  • 웹 서버로 Node.js를 사용하는 경우 Json 형식의 데이터를 주고 받기 때문에 Json 형식의 데이터와 Java 객체 사이의 변환 작업이 필수적이다.

  • 이를 해결한 것이 Volley, OkHttp, Gson 등의 라이브러리이다.

    • Volley 라이브러리의 경우 HttpUrlConnection의 기본 코드와 스레드&핸들러를 내부적으로 관리하기 때문에 개발자가 직접 스레드와 핸들러를 생성하고 관리할 필요가 없어 매우 편리하고 안정적으로 코드를 작성할 수 있다.

    • Gson 라이브러리는 Json 형식의 데이터를 Java 객체로 변환하는 기능을 지원하기 때문에 몇 줄의 코드 만으로 쉽게 변환할 수 있다.

 

+ Volley에서 필요한 RequestQueue 사용법

  • 이미 넣은 요청을 빼거나 요청 순서를 변경하는 등 조작하는 것이 가능하지만 몇 가지 제약이 있다.

  • Application 클래스를 오버라이딩해서 클래스 안에 static으로 RequestQueue를 선언한 뒤 사용하는 것이 일반적이다. (물론 Application이 아닌 다른 특정 클래스에서 static으로 선언해서 사용할 수도 있다.)

 

2. 이미지 업로드/다운로드 작업에도 많은 기본 작업이 필요하다.

  • 실무에 웹 통신을 적용하다 보면 일반 문자열 데이터가 아닌 이미지나 파일 자체를 주고 받아야 하는 경우가 생긴다.

  • 이미지 업로드를 위해서 Multipart 전송을 통해 서버에 업로드 하는 방식이 있고, 이미지 다운로드를 편하게 사용하기 위해 Universal Image Loader, Glide, Picasso 등의 라이브러리가 있다.

 

 

 

[이미지 업로드/다운로드]

이미지 업로드/다운로드 작업은 사실상 File을 업로드/다운로드 하는 작업이다.

 

안드로이드에서 웹 서버로 이미지를 업로드하기 위해서는 multipart 표준 프로토콜을 이용한다. 

 

Multipart는 Http 통신을 통해 File을 서버로 전송하기 위해 사용되는 Content-type이다. Http는 간단하게 Request Line / Http Header / Empty Line / Message body로 구분할 수 있는데, 여기서 Message body에 들어가는 타입을 Http Header에서 명시할 수 있도록 해주는 필드가 Content-type이다. Content-type를 multipart로 지정하면 여러 타입(텍스트+이미지 또는 이미지 여러 개 등)의 데이터를 묶어서 보낼 수 있게 된다. 그러면 Message body에서 Http Header에 정의된 구분자로 여러 개의 데이터를 구분해서 보내게 되고, 이를 서버에서 파싱해서 받을 수 있다.

 

물론 라이브러리를 잘 활용하면 http와 multipart 프로토콜을 이해하고 Http 전문을 작성해서 서버로 보내는 작업을 하지 않아도 된다. 예를 들어 아래의 라이브러리를 사용하면 MultipartUploadRequest를 단순하게 구현할 수 있다.

implementation 'net.gotev:uploadservice:3.4.1'
implementation 'in.gauriinfotech:commons:1.1.3'
try {
    String uploadId = UUID.randomUUID().toString();
    new MultipartUploadRequest(this, uploadId, url)
            .addFileToUpload(path, name)
            .addParameter("name", name)
            .setNotificationConfig(new UploadNotificationConfig())
            .setMaxRetries(2)
            .startUpload();
} catch (Exception exc) {
    Toast.makeText(this, exc.getMessage(), Toast.LENGTH_SHORT).show();
}

 

만약 라이브러리를 사용하지 않고 파일을 Stream으로 올리는 경우, 파일의 크기가 크면 파일을 업로드 하는 중에 Stream이 끊어지는 문제가 발생할 수 있다. 하지만 이 라이브러리를 사용하면 이런 문제를 알아서 처리해주기 때문에 안정적으로 업로드할 수 있다는 장점이 있다.

 

 

안드로이드에서 이미지를 다운로드 받는 작업은 어렵지 않다. 하지만 가져올 이미지가 많을 때 생기는 부하나 캐싱 등 성능에 관련된 문제를 여러 라이브러리에서 해결해 주기 때문에 Glide, Picasso와 같은 라이브러리를 사용하는 것이 편리하다.

 

Glide와 Picasso를 사용하는 예제는 다음과 같다.

// Glide
implementation 'com.github.bumptech.glide:glide:4.8.0’ 
annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

// Picasso
implementation 'com.squareup.picasso:picasso:2.71828'

먼저, 위의 코드를 dependency에 추가해 주고, 아래 코드처럼 Glide와 Picasso를 사용해서 이미지를 로딩할 수 있다.

public void getWithGlide() {
    String url = editText.getText().toString();
    Glide.with(this).load(url).into(imageView); 
}

public void getWithPicasso() {
    String url = editText.getText().toString();
    Picasso.get().load(url).into(imageView); 
}

 

 

 

 

실시간 메시징

 

옛날 메신저들은 웹 서버의 성능이 좋지 않았기 때문에 대부분 소켓 서버를 이용했다. 웹 통신에서 소켓 연결을 만들었다가 끊어버리는 데 리소스를 많이 먹어서 서버 부하가 컸기 때문이다. 하지만 소켓 서버는 thread를 직접 다루고 비동기 작업을 사용하면서 코드가 복잡해지는 등의 문제가 많았다. 

원래의 웹 브라우저는 서버 쪽과 연결을 만든 뒤 데이터를 주고 받고 나서 연결을 끊어버렸다. (stateless 방식) 이 방식은 웹 페이지 하나를 주고 받을 때는 문제되지 않지만, 실시간 메시지를 주고 받을 때 처럼 주고 받는 데이터가 작고 빈번한 상황에서 성능이 매우 떨어졌다.

 

그러다 Html5에서 애플리케이션 레벨에서 소켓을 연결할 수 있는 웹 소켓이 등장했다. 웹 소켓을 이용해서 실제로 연결이 끊어지더라도 가상으로 연결이 유지되는 것 처럼 만들어주기 때문에 웹 소켓을 이용해 웹 브라우저 채팅이 가능하게 되었다.

웹 브라우저를 모바일에서 WebView나 임베디드 방식으로 실행시킬 수 있기 때문에 모바일에서도 실시간 채팅이 가능해졌다.

 

웹 소켓 서버는 일반 소켓 서버와 구성 방식이 다르다. 아래 그림처럼 Http Header를 이용해 정보를 교환한다. 

 

하지만 직접 Http 헤더를 조작하지 않고 Socket.IO 라이브러리를 사용하면 웹 소켓 서버와 웹 소켓 클라이언트를 통해 실시간 채팅을 쉽게 구현할 수 있다. (보안 이슈로 Http 내용을 모두 이해하고 조작해야 하는 경우는 라이브러리를 사용하지 않고 직접 구현하는 것이 바람직하다.)

Socket.IO를 이용해 웹 소켓을 구현할 때는 Json 형식의 데이터를 emit(send) 메서드와 on(receive) 메서드로 주고 받는다.

 

메시징을 실무에서 사용하면 다음과 같은 이슈가 발생할 수 있다.

 

1. 사용자가 많을 때 생기는 문제

  • 네트워크 비용이 많아져 서버에 부하가 생긴다.

  • 서버 부하를 해결하기 위해 서버를 증설하게 되고, 서버 증설 시 각 서버에 등록 되어 있는 사용자끼리 연결이 되어 있어야 서로 채팅이 가능하다.

    • 이에 대한 해결책으로 여러 서버에서 하나의 데이터베이스를 이용하는 방식을 사용한다.

    • 하지만 실시간 통신은 읽고 쓰는 속도가 빨라야 하기 때문에 디스크를 읽고 쓰는 일반 DBMS와 다르게 메모리에 데이터를 읽고 쓰는 방식으로 동작하는 Redis를 사용한다.

    • 데이터 베이스를 통해 사용자를 관리하고 들어온 데이터 내용을 관리하면서 데이터가 전송되지 않은 경우에 재전송을 하는 등의 오류에 대한 처리를 할 수 있다.

 

2. 서버 부하를 낮추는 방법

  • 실시간 메시징 서비스에서 서버 부하를 낮추는 가장 효율적인 방법은 단말 간 통신인 P2P 모델을 적용하는 것이다.

  • WebRTC - 하이브리드 P2P 방식의 메시지, 오디오, 비디오 전송 메커니즘을 제공한다. 그렇기 때문에 실시간 채팅은 물론 화상 채팅도 가능하다.

    • Html5 표준으로 등록되었고 라이브러리도 안정화된 상태라 이미 WebRTC를 이용한 서비스가 많이 나왔다.

    • 한 가지 문제는 세션 연결 기능을 지원하지 않아서 어느 단말과 연결하는지를 알려줘야 한다는 것이다.

      • Node.js 서버를 구성하고 단말 간 세션을 연결하는 작업을 직접 작성해야 한다.

      • 세션 연결 작업을 프로토콜을 보며 직접 구현할 수도 있지만 이에 대한 라이브러리를 사용할 수도 있다.

    • 클라이언트 쪽에서 WebRTC를 구성하기 위한 라이브러리를 사용하면 편리하게 구현이 가능하다.

  • 방화벽 문제 & 망의 분리 문제

    • STUN, TURN, ICE 등의 프로토콜을 이용해 해결해야 한다.

    • 하지만 프로토콜이 단순해지면서 이 기능이 기본적으로 WebRTC에 포함되었다.

 

메시징을 구현할 때 소켓을 이용한 자체 프로토콜 방식을 사용한다면 대부분의 기능을 최적화 할 수 있지만, 시간과 비용의 소모가 크고 서버 부하 이슈를 직접 해결해야 하기 때문에 필요에 따라 라이브러리를 적절히 이용하면서 구현하는 것이 바람직하다.

 

 

EasyRTC라는 WebRTC 오픈소스가 존재하기 때문에 찾아서 직접 설치한 뒤 실행해 볼 수 있다.

EasyRTC는 웹 브라우저, 모바일 단말 등 여러 클라이언트에서 서로 네트워크 망이 다르더라도 실시간 메시징이 가능하다.

실습을 위한 클라이언트(웹 브라우저, 모바일 등) demo 코드가 존재한다. 

demo_instant_messaging.html > 실시간 채팅 예제

demo_audio_video.html > 화상 채팅 예제

 

이처럼 EasyRTC 오픈소스를 이용하면 단말 간의 실시간 채팅과 화상채팅을 구현할 수 있다.

 

 

 

 

 

YouTube 실시간 방송/재생

 

네트워킹을 통해 데이터를 주고 받는다고 할 때 빠질 수 없는 주제가 영상 스트리밍이다. 영상은 기본적으로 크기가 매우 크기 때문에 데이터를 주고 받는 작업의 부하가 크다. 그렇기 때문에 영상을 주고 받기 위해 스트리밍 서버가 필요한데, 스트리밍 서버가 클라이언트에서 영상 스트림을 받아서 다른 단말로 보내주는 역할을 하는 것이다. 클라이언트와 스트리밍 서버를 연결하고 RTSP나 RTMP와 같은 프로토콜을 통해 실시간 방송 서비를 할 수 있게 되는데, 스트리밍 서버를 구현하기 위해 Red5나 Darwin 등 오픈소스가 존재한다. 스트리밍 서버를 사용하기 위해 오픈소스로 직접 구현하는 방법도 있지만,  와우자 스트리밍 엔진이나 kurento media server 등 스트리밍 기능을 지원하는 상용 서버를 사용하는 방법도 있다.

 

하지만 스트리밍 서버는 큰 영상 데이터를 주고 받기 때문에 네트워크 비용이 많이 발생하기 때문에 이를 실제 앱으로 서비스하는 것이 쉽지 않다. 그래서 YouTube나 Facebook에서 자신들의 스트리밍 서버를 사용해서 영상 서비스 앱을 만들 수 있도록 API를 제공한다. API를 이용해 서비스를 만들게 되면 비용 없이 서비스를 만들 수 있으나 YouTube나 Facebook에 종속된다는 단점이 있다. 하지만 장점을 이용해서 만들어진 앱 중에 YouTube Red라는 유료 앱이 있는데, YouTube Red 앱은 YouTube로 음악을 듣기 위해 영상을 광고 없이 백그라운드에서 재생할 수 있다. 이 앱도 YouTube API에서 제공하는 검색/재생 기능을 이용해 커스터마이징 해서 만들어졌다.

YouTube 영상 재생을 위해서는 레이아웃에서 <YouTubePlayerView>를 추가한 뒤 해당 액티비티가 YouTubeBaseActivity를 상속하도록 수정해주면 된다. 그리고 액티비티 코드에서 YouTubePlayerView를 초기화한 뒤 비디오를 로드하는 작업은 아래와 같이 몇 줄의 코드만으로도 구현이 가능하다.

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    playerView = findViewById(R.id.playerView);
    playerView.initialize(API_KEY, new YouTubePlayer.OnInitializedListener() { 
        @Override
        public void onInitializationSuccess(YouTubePlayer.Provider provider, YouTubePlayer youTubePlayer, boolean b) {
            player = youTubePlayer;
            player.setPlayerStateChangeListener(new YouTubePlayer.PlayerStateChangeListener() { 
            	@Override
                public void onLoaded(String id) {
                    player.play();
                }
                ...
            });
            ...
        }
        ...
    });

    Button startButton = findViewById(R.id.startButton);
    startButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            player.cueVideo(videoId);
        }
    });
}

 

여기서 영상을 재생하는 기능은 방송을 소비하는 쪽의 기능인데, 만약 방송을 제공하는 기능을 만들어야 할 때는 조금 더 복잡해진다. 왜냐하면 YouTube에서 방송 채널을 만들고 그 방송 채널과 연결하는 기능까지는 API로 제공하지만 영상이나 음성을 YouTube 서버로 보내는 기능은 제공하지 않기 때문이다. Intent를 통해 YouTube 앱으로 이동해서 YouTube 방송 화면으로 이동하도록 할 수는 있지만 이 방법은 자신이 만든 앱에서 방송을 제공하는 것이 아니라 YouTube 앱으로 화면을 전환한 것 뿐이다. 그렇기 때문에 자신의 앱에서 방송 영상을 제공하도록 하고 싶다면 직접 RTMP 프로토콜을 사용해 스트리밍 서버와 연결하는 스트리밍 코드를 작성해야 한다. 스트리밍 코드를 작성하는 데에도 오픈소스가 있기 때문에 오픈소스를 잘 사용하면 비교적 쉽게 방송 앱을 구현할 수 있다.

 

 

 

이렇게 강의대로 네트워크에 대한 전반적인 내용을 이론적으로 한 번 훑어 보았는데, 이 내용을 알아 두고 나중에 필요하게 됐을 때 도움이 된다면 좋을 것 같다.

 

 

 

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함