2021년 3월 24일 수요일

[Golang] net/http 패키지를 이용한 웹서버 제작

 net/http 패키지를 이용한 웹서버 제작

golang에서 기본적으로 제공하는  net/http패키지를 이용해서 웹서버를 구축할수 있다. 일단 얼마나 간단한지 보자.

1.초간단 서버 구동 

package main

import (
  "fmt"
  "net/http"
)

func main() {
  http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
      fmt.Fprintln(w, r.Method, "welcome Go lang")
  })
  http.ListenAndServe(":8080", nil)
}

/*
or 

import "log"
fun printHello(w http.ResponseWriter, r *http.Request) {
      fmt.Fprintln(w, r.Method, "welcome Go lang"
}
func main() {
  http.HandleFunc("/", printHello)

   if err := http.ListenAndServe(":8000", nil); err != nil {
        log.Fatal("ListenAndServe: ", err)
    }

}

*/

 

웹서버를 구동할수 있는 net/http 패키지를 제공하기 때문에 단 몇줄만으로도 웹서버를 구동하여 응답문자와 접속메소드를 출력할수 있다.

간단한 echo(응답) 서버이지만 , 여러개의 endpoint를 생성한다면 간단한 API서버를 금방 만들수 있다. 

API서버는 여러개의 endpoint를 가지는데 다루기쉬운 Restful(패스파라메터와 요청파라메터로 구성된) 방식으로 만들기 위해서는 Router라는 것을 만들어 사용자가 요청한 페이지와 파라메터에 맞게 적절한 응답을 해주어야 한다.


  1. net/http
    net / http 패키지는  HTTP 클라이언트와 HTTP 서버를 구현하는 데 필요한 기능을 제공하고 있다. 

  2. http.ListenANdServe
    서버를 기동 시겨준다. 

  3. HandlerFunc
    golang에서 제공하는 기본적인  주소매칭방식인 DefaultServeMux 으로 url주소패턴과 실행될 함수를 지정한다.
    두번째 인자로 handler 를 받게 되는데 이곳에서 응답처리와 클라이언트로부터의 요청에 대한 처리를 수행한다.

    pattern : url 패턴이다
    handler : Reponse(응답) 과  Request(요청된것) 을 인자로 받는 함수이다.

  4. Handle
    HandlerFunc 는 항상 지정된 같은 함수의 루틴일 실행하게 되는데, 같은 url패턴이라도 상황에 따라, 예를들면  로그인전/후의 메인페이지  등과 같이 다른 내용을 보여야 할떄가 있다. 이럴때는 처리해서 보여줄 페이지를 동적으로 구성해야 하는데 Handle 함수의 두번째 인자에 ServerHttp 메소드를 가진 구조체를 지정해주면 된다.

package main

import (
  "fmt"
  "net/http"
)

type RessonseMessage string

func (s RessonseMessage) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  fmt.Fprint(w, s)
}
func main() {
  helloServer := RessonseMessage("hi. there")

  http.Handle("/", helloServer)
  http.ListenAndServe(":8000", nil)
}

 



Handle

 

2.경로에 따라서 다르게 응답하는 서버  

net/http로 요청에 응답을 하는 방식은 HandleFunc  또는  Handle 함수에 두번쨰 인자로 함수를 건네주면된다.

함수를  인터페이스 형식으로 건네주고 싶을 때는 type을 사용한다.
https://github.com/sugoigroup/study_golang/tree/http

type fooHandler struct{}


func Runserver() {


     mux := http.NewServeMux()

     mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {

        fmt.Fprint(w, "Hello World")

     })


     mux.Handle("/foo", &fooHandler{})


     http.ListenAndServe(":3000", mux)


}


func (f *fooHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {

  fmt.Fprint(w, strutils.ToUpperCase("Hello Foo!"))

}

3.url 에 입력된 파라메터를 읽기  

보통 url에 파라메터를 붙여 서버에 어떤 값을 전송한다. 간단히 url query에서 값을 가져와보자. 간단하다.

func Runserver() {

     mux := http.NewServeMux()

     mux.HandleFunc("/bar", barHandler)

     http.ListenAndServe(":3000", mux)

}


func barHandler(w http.ResponseWriter, r *http.Request) {

  name := r.URL.Query().Get("name")

  if name == "" {

     name = "world"

  }

  fmt.Fprintf(w, "Hello %s!", name)

}

4.응답을  html 로 하기   

보통 url에 파라메터를 붙여 서버에 어떤 값을 전송한다. 간단히 url query에서 값을 가져와보자. 간단하다.

func Runserver() {


     mux := http.NewServeMux()

     mux.HandleFunc("/bar", barHandler)

     http.ListenAndServe(":3000", mux)


}


func barHandler(w http.ResponseWriter, r *http.Request) {

  name := r.URL.Query().Get("name")

  if name == "" {

     name = "world"

  }

  w.Header().Set("Content-Type", "text/html") // HTML 헤더 설정

  w.Write(htmlMessage(name))

}


func htmlMessage(msg string) []byte {

  // HTML로 웹 페이지 작성

  html := `

  <html>

  <head>

     <title>Hello</title>

  </head>

  <body>

     <div style='text-align:center'><b>Hello ` + msg + `</b></div>

  </body>

  </html>

  `

  return []byte(html)

}


[Android] Flavors 간단 사용법

 Flavors

각상황(Dev, Stage, Product) 별로 패키지명과 리소스/API주소등을 달리하고 싶을때


앱빌드시에 테스터에게 전달할 파일따로/ 리리스용 파일따로 분리해서 리소스도 다르게 해서 패키징 하고 싶을때가 있다.
이떄 Gradle 의 Android속성중에 productFlavors 라는걸 이용하면 각 상활별로 APK 를 만드는게 가능하다.


사용예


   flavorDimensions "environment"


   productFlavors {

       dev {

           dimension "environment"

           applicationIdSuffix ".free"

           manifestPlaceholders = [ appLabel: "Dev" ]

           resConfigs "ko"

           minSdkVersion 23

       }


       stage {

           dimension "environment"

           applicationIdSuffix ".stage"

           manifestPlaceholders = [ appLabel: "Stage" ]

           resConfigs "en", "ko"

           minSdkVersion 19


       }

       product {

           dimension "environment"

           applicationIdSuffix ".product"

           manifestPlaceholders = [ appLabel: "Product" ]

           resConfigs "en", "ko", "ja"

           minSdkVersion 19


       }

   }

어플리케이션고유아이디, 앱이름, 첨부될 리소스구분, 그밖의 android 관련 설정을 각각 할수 있다.
또한 설정파일은 앱소스코드에서 BuildConfig를 통해 설정값을 읽어 올수도 있다.

flavorDimensions을 여러개 지정한다면, 저정된 개수에 Flavors에 정의된 각각의 모든 경우를 고려한 개수만큼 빌드실행변수가 생성된다.


flavorDimensions "serverSet", "whichBuild"

productFlavors {
amazon {
dimension "serverSet"
}
gcp {
dimension "serverSet"
}

product{
dimension "whichBuild"
}
dev{

dimension
"whichBuild"
}
}
이고
buildType {
release {}
debug {}
qa {}
}

로 설정하면
- Build variants에
amazonProductDebug
amazonProductRelease
amazonProductQA
amazonDevDebug
amazonDevRelease
amazonDevQA


gcpProductDebug
gcpProductRelease
gcpProductQA
gcpDevDebug
gcpDevRelease
gcpDevQA
가 생성되어 환경에 맞게 빌드하여 사용하면된다.

프로그램에서는 Build.xxxx로 사용한다.
빌드하면 자동으로 생성되는 파일인 BuildConfig.java에 아래와 같이 정의되어 있다.
public final class BuildConfig {
...
public static final String BUILD_TYPE = "debug";
public static final String FLAVOR = "amazonDev";
public static final String FLAVOR_serverSet = "amazon";
public static final String FLAVOR_gcp = "dev";
}

2021년 3월 17일 수요일

[Android] Kotlin & Android 기초 강좌 -작업중-

작성중임

2021년 3월 10일 수요일

[Android] Deeplink 를 android studio 에서 테스트 하기

  Run > Edit Configurations 


해서 

Launch -> URL(또는 deeplink?) -> 주소란에 tutsplus://deeplink 


물론 사전에 소스에서 인텐트필터로 위의 주소로 왔을떄 받아들일 준비를 해야한다.


    <activity android:name="com.example.matthew.deeplinks.LinkActivity" android:label="@string/title_activity_link"

        android:theme="@style/AppTheme.NoActionBar">

        <intent-filter>

            <action android:name="android.intent.action.VIEW" />

            <category android:name="android.intent.category.BROWSABLE" />

            <category android:name="android.intent.category.DEFAULT" />


            <!-- URI tutsplus://deeplink -->

            <data android:scheme="tutsplus" android:host="deeplink"/>

            <!-- URI https://www.mydeeplink.com -->

            <data android:scheme="http" android:host="www.mydeeplink.com"/>

        </intent-filter>

    </activity>


그리고 title_activity_link 에서는 

 Intent in = getIntent();

Uri data = in.getData(); 

String x;

String y;

if (uri != null) {

  x = data.getQueryParameter("x"); // x = "1.2"

  y = data.getQueryParameter("y"); // y = "3.4"

}


또는

String deeplinkUrl = in.getDataString();

하면 딥링크를통해 왔는지 알수 있다.

kakoya 서버 cent6 64bit rtmp nginx

 rtmp 설정 

https://juyoung-1008.tistory.com/31

1.nginx

wget http://nginx.org/download/nginx-1.7.5.tar.gz


2.rtmp get 

wget https://github.com/arut/nginx-rtmp-module/archive/master.zip

3.unzip 이 없다면 

yum install unzip

4.혹시 yum 이 안되면 

vi /etc/yum.repos.d/CentOS-Base.repo

# CentOS-Base.repo
#
# The mirror system uses the connecting IP address of the client and the
# update status of each mirror to pick mirrors that are updated to and
# geographically close to the client.  You should use this for CentOS updates
# unless you are manually picking other mirrors.
#
# If the mirrorlist= does not work for you, as a fall back you can try the 
# remarked out baseurl= line instead.
#
#

[base]
name=CentOS-$releasever - Base
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=os&infra=$infra
baseurl=http://vault.centos.org/centos/$releasever/os/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#released updates 
[updates]
name=CentOS-$releasever - Updates
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=updates&infra=$infra
baseurl=http://vault.centos.org/centos/$releasever/updates/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#additional packages that may be useful
[extras]
name=CentOS-$releasever - Extras
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=extras&infra=$infra
baseurl=http://vault.centos.org/centos/$releasever/extras/$basearch/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#additional packages that extend functionality of existing packages
[centosplus]
name=CentOS-$releasever - Plus
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=centosplus&infra=$infra
baseurl=http://vault.centos.org/centos/$releasever/centosplus/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6

#contrib - packages by Centos Users
[contrib]
name=CentOS-$releasever - Contrib
#mirrorlist=http://mirrorlist.centos.org/?release=$releasever&arch=$basearch&repo=contrib&infra=$infra
baseurl=http://vault.centos.org/centos/$releasever/contrib/$basearch/
gpgcheck=1
enabled=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6


5. nginx 도 풀고 

tar -zxvf nginx-1.7.5.tar.gz

6. nginx 폴더에서 rtmp 모듈 추가

./configure --add-module=/path/to-nginx/rtmp-module --with-debug --with-http_ssl_module


7. gcc가 없다면 (그리고 다시6)

 yum install gcc

8. error 라면

./configure: error: the HTTP rewrite module requires the PCRE library.

yum -y install pcre-devel

9.제길 귀찮다 . 개발 툴 다 설치하자.

# yum groupinstall "Development Tools"

# yum install pcre-devel openssl-devel libxslt-devel gd-devel perl-ExtUtils-Embed epel-release

# yum install GeoIP-devel

10.그리고 다시6

Configuration summary

  + using system PCRE library

  + using system OpenSSL library

  + md5: using OpenSSL library

  + sha1: using OpenSSL library

  + using system zlib library


  nginx path prefix: "/usr/local/nginx"

  nginx binary file: "/usr/local/nginx/sbin/nginx"

  nginx configuration prefix: "/usr/local/nginx/conf"

  nginx configuration file: "/usr/local/nginx/conf/nginx.conf"

  nginx pid file: "/usr/local/nginx/logs/nginx.pid"

  nginx error log file: "/usr/local/nginx/logs/error.log"

  nginx http access log file: "/usr/local/nginx/logs/access.log"

  nginx http client request body temporary files: "client_body_temp"

  nginx http proxy temporary files: "proxy_temp"

  nginx http fastcgi temporary files: "fastcgi_temp"

  nginx http uwsgi temporary files: "uwsgi_temp"

  nginx http scgi temporary files: "scgi_temp"

11.make

12.make install

13. RTMP URL format

rtmp://rtmp.example.com/app/[/name]

app - 설정파일의 하나의 application 이름과 같아야 한덴다.

name - 설정하게 되면 개별의 방송을 할 수 있습니다. ( 방개념이란다) streamkey이기도하다.

14.ffmpeg도 해두자 .영상 저장 혹은 로컬 영상 배포용이다.

yum install ffmpeg

15. 이제 nginx에 rtmp 포트및 기타 설정하자.

심플한 사용방법은 이렇다 

....


rtmp {

        server {

                        listen 1935; # Listen on standard RTMP port

                        chunk_size 4000;


                application show {

                        live on;

                        allow publish all;

#                       # Turn on HLS

                        hls on;

                        hls_path /mnt/hls/;

                        hls_fragment 3;

                        hls_playlist_length 60;

#                       # disable consuming the stream from nginx as rtmp

                        deny play all;

                }

        }

}


http{
...

-일단 간단하게 서버의 파일을 스트리밍 하는걸로 해보자 ffmpeg가 짱이다.

wget https://file-examples-com.github.io/uploads/2017/04/file_example_MP4_640_3MG.mp4

ffmpeg -re -i example-vid.mp4 -vcodec libx264 -vprofile baseline -g 30 -acodec aac -strict -2 -f flv rtmp://너의서버아이피겠쥐?/show/stream

하고 나서 obs나 rtmp뷰어 앱 등에서 확인하면 잘 돌아가는걸 볼수 잇다.

또한 OBS 나 rtmp 배신 프로그램이 있다면 그걸 이용해서 실시간 방송도 할수 있다. 
OBS라면 settting->Stream->Service[custom]->Server[ rtmp://너의아이피/nginx에서 설정한application이름/스트리밍할때지정한키(또는룸이름)] 
으로 지정하고 Start streaming 하면 방송이 되고 또 그걸 rtmp뷰어앱등에서 실시간으로 영상이 보인다.
rtmp {

    server {

        listen 1935;

        chunk_size 4000;

        # TV mode: one publisher, many subscribers
        application mytv {

            # enable live streaming
            live on;

            # record first 1K of stream
            record all;
            record_path /tmp/av;
            record_max_size 1K;

            # append current timestamp to each flv
            record_unique on;

            # publish only from localhost
            allow publish 127.0.0.1;
            deny publish all;

            #allow play all;
        }

        # Transcoding (ffmpeg needed)
        application big {
            live on;

            # On every pusblished stream run this command (ffmpeg)
            # with substitutions: $app/${app}, $name/${name} for application & stream name.
            #
            # This ffmpeg call receives stream from this application &
            # reduces the resolution down to 32x32. The stream is the published to
            # 'small' application (see below) under the same name.
            #
            # ffmpeg can do anything with the stream like video/audio
            # transcoding, resizing, altering container/codec params etc
            #
            # Multiple exec lines can be specified.

            exec ffmpeg -re -i rtmp://localhost:1935/$app/$name -vcodec flv -acodec copy -s 32x32
                        -f flv rtmp://localhost:1935/small/${name};
        }

        application small {
            live on;
            # Video with reduced resolution comes here from ffmpeg
        }

        application webcam {
            live on;

            # Stream from local webcam
            exec_static ffmpeg -f video4linux2 -i /dev/video0 -c:v libx264 -an
                               -f flv rtmp://localhost:1935/webcam/mystream;
        }

        application mypush {
            live on;

            # Every stream published here
            # is automatically pushed to
            # these two machines
            push rtmp1.example.com;
            push rtmp2.example.com:1934;
        }

        application mypull {
            live on;

            # Pull all streams from remote machine
            # and play locally
            pull rtmp://rtmp3.example.com pageUrl=www.example.com/index.html;
        }

        application mystaticpull {
            live on;

            # Static pull is started at nginx start
            pull rtmp://rtmp4.example.com pageUrl=www.example.com/index.html name=mystream static;
        }

        # video on demand
        application vod {
            play /var/flvs;
        }

        application vod2 {
            play /var/mp4s;
        }

        # Many publishers, many subscribers
        # no checks, no recording
        application videochat {

            live on;

            # The following notifications receive all
            # the session variables as well as
            # particular call arguments in HTTP POST
            # request

            # Make HTTP request & use HTTP retcode
            # to decide whether to allow publishing
            # from this connection or not
            on_publish http://localhost:8080/publish;

            # Same with playing
            on_play http://localhost:8080/play;

            # Publish/play end (repeats on disconnect)
            on_done http://localhost:8080/done;

            # All above mentioned notifications receive
            # standard connect() arguments as well as
            # play/publish ones. If any arguments are sent
            # with GET-style syntax to play & publish
            # these are also included.
            # Example URL:
            #   rtmp://localhost/myapp/mystream?a=b&c=d

            # record 10 video keyframes (no audio) every 2 minutes
            record keyframes;
            record_path /tmp/vc;
            record_max_frames 10;
            record_interval 2m;

            # Async notify about an flv recorded
            on_record_done http://localhost:8080/record_done;

        }


        # HLS

        # For HLS to work please create a directory in tmpfs (/tmp/hls here)
        # for the fragments. The directory contents is served via HTTP (see
        # http{} section in config)
        #
        # Incoming stream must be in H264/AAC. For iPhones use baseline H264
        # profile (see ffmpeg example).
        # This example creates RTMP stream from movie ready for HLS:
        #
        # ffmpeg -loglevel verbose -re -i movie.avi  -vcodec libx264
        #    -vprofile baseline -acodec libmp3lame -ar 44100 -ac 1
        #    -f flv rtmp://localhost:1935/hls/movie
        #
        # If you need to transcode live stream use 'exec' feature.
        #
        application hls {
            live on;
            hls on;
            hls_path /tmp/hls;
        }

        # MPEG-DASH is similar to HLS

        application dash {
            live on;
            dash on;
            dash_path /tmp/dash;
        }
    }
}

------------------------------------



에러가 날떄.

1.Failed to set locale, defaulting to C 는 

export LC_ALL=C

yudo yum check


2.centos6레포에러..

sed -i "s/mirrorlist=https/mirrorlist=http/" /etc/yum.repos.d/epel.repo

yum -y install epel-release


3.혹시 포트 열었는지 


-A INPUT -m state --state NEW -m tcp -p tcp --dport 80 -j ACCEPT

-A INPUT -m state --state NEW -m tcp -p tcp --dport 1935 -j ACCEPT

/etc/init.d/iptables restart

2021년 3월 3일 수요일

[React Native] 'event2/event-config.h' file not found

 brew install watchman

brew install yarn

npm install -g react-native-cli

react-native init AwesomeProject

cd AwesomeProject

react-native run-ios


했더니, flipper관련 뭐가 막뜬다..머래 ㅆㅂ


Podfile의   use_flipper! 를 use_flipper!('Flipper' => '0.74.0')로 바꾸고 

pod install 함


그리고 다시 해보면 실행됨..

2021년 3월 1일 월요일

[Kotlin] try, catch 대신 runcatch

 참고 사이트 : https://uchun.dev/runCatching%EC%9D%84-%EC%9D%B4%EC%9A%A9%ED%95%9C-kotlin%EC%97%90%EC%84%9C-exception%EC%B2%98%EB%A6%AC-%EB%B0%A9%EB%B2%95/

kotlin 에서 기존의 try catch 도 가능하지만 

val fruitName = try {

    getRandomFruit()

} catch (throwable: Throwable) {

    ""

}


ex 

return runCatching {
if (argParam.isEmpty()) {
method?.invoke(null) as T?
} else {
method?.invoke(obj, null) as T?
}

}.getOrNull()

코드가 정말 깔끔해진다

[Unity] Firebase 6.15 를 사용한 프로젝트는 unity 2018 버젼을 사용해서 android export해야 되더라

 Firebase 6.15 를 사용한 프로젝트를 최신버젼에서 가져와서 돌려보려 했더니 안되더라, 

 unity 2018 버젼을 사용해서 android export해야 되더라


그리고 혹시모르니 external dependency manager 에서 android Resolver (먼제 Delete Resolved Libraries 하고) 해주면 좋음

2021년 2월 24일 수요일

[iOS] @synchronized 배타 제어 (객체 동시접근 방지)

참고: https://dolfalf.tistory.com/145

https://aroundck.tistory.com/4705


가장간단한건 

 // self를 키로 락을 검. 어디선가 self로 락을 건경우 락이 해제될 때까지 여기서 기다리게됨.
@synchronized (self) {
  [_mutableItems addObject:object];
}


보통 이런식으로도 씀.

@implementation MyClass

{

// 잠금시 키로 지정하는 인스턴스를 저장할 위치를 제공합니다.

NSObject * _objectForLock;

}


이것을 init 메소드 등의 어딘가 적절한 위치로 초기화합니다.

- (id) init

{

self = [super init];


if (self)

{

// 잠금시 키로 지정하는 인스턴스를 준비합니다.

_objectForLock = [[NSObject alloc] init];

}

return self;


}


ARC 환경이라면 Objective-C 인스턴스는 필요하지 않을 때 출시되므로 뒤처리가 필요하지 않습니다.


ARC 환경이 아닌 경우는 -dealloc 메소드 등으로 잠금을 확보 한 인스턴스를 release하도록합니다.


@synchronized의 인수로 사용합니다.


@synchronized (_objectForLock)

{


}


Effective Object-C 에서는 

_syncQueue = dispatch_queue_create("com.effectiveobjectivec.syncQueue", NULL); 

이렇게도 쓰라고함

2021년 2월 21일 일요일

[iOS] 개발/테스트 배포용 ipa 간단 생성

Product->Archive->Distribute App -> Developement ->쭉쭉 다음으로 넘기고

실행하는 쪽은 Xcode->Devices and Simulators 에서 ipa던져넣으면 된다.