procket/examples/sendmsg_recvmsg_echo.erl 動かしてみた

結果から書くと、動いた?となる。

まず、自身の現時点の知識だと、何故動いているのか、理解していない。

だから、ここで、理屈を書く事はできない。

あくまでも、動いたソースの保存として書いておく。

将来何かで実装するときは、こう書かないかも知れない。

-module(sample).

-export([start/0]).

-define(PORT, 8854).

-define(SIZEOF_SOCKADDR, sizeof(sockaddr)).

start() ->
    {ok, FD} = procket:socket(inet, dgram, udp),
	io:format("SIZEOF_SOCKEADDR: ~p~n", [?SIZEOF_SOCKADDR]),

    ok = procket:setsockopt(FD, 'SOL_SOCKET', 'SO_REUSEPORT', <<1:32>>),
    Family = procket:family(inet),
    io:format("inet family ~p~n", [Family]),

    SA = <<(procket:sockaddr_common(inet, 16)):2/bytes, ?PORT:16/integer-unsigned-big,  192, 168, 0, 1, 0:64>>,
	io:format("SA: ~p~n", [SA]),
    ok = procket:bind(FD, SA),
    loop(FD).

loop(FD) ->
    %% recv a packet up to 512 bytes long, along with 512 bytes of control
    %% data
    case procket:recvmsg(FD, 512, 0, 512, ?SIZEOF_SOCKADDR) of
        {error, eagain} ->
            loop(FD);
        {ok, Buf, Flags, CtrlData, From} ->
            io:format("Buffer ~p, From ~p, Ctrldata ~p Flags ~p~n", [Buf,
                                                                     From,
                                                                     CtrlData,
                                                                     Flags]),
            %% echo the packet back, but set the destination address to the
            %% 'from' of the previous packet, and send the previous message's
            %% control data so that the source address is set to the
            %% destination address of the previous packet
            ok = procket:sendmsg(FD, Buf, 0, CtrlData, From),
            loop(FD)
    end.

sizeof(sockaddr) ->
    case os:type() of
        {unix,sunos} -> 32;
        {unix,_} -> 28
		end.

検索しまくっていろいろブックマークをしまくったけど、大半、知識不足で理解できなかった_| ̄|○

https://github.com/msantos/procket/issues/27

どうも、procketの作者さん自身が答えてくれているらしいが、IP4での接続周りは、これで解消できました。

あとは、あんまり弄ってません。でも、2日掛かりました。

さて、自分が分かってない部分。

SAの変数で扱っている関数、procket:sockaddr_common、0:64

recvmsg, sendmsgの詳しい動き、sockaddrとかいうアトムとか・・・

'SOL_SOCKET', 'SO_REUSEPORT'とか、ちんぷんかんぷん。
http://umezawa.dyndns.info/wordpress/?p=2609
より、ヒントをもらって、書いたけど、分かってないです。

(´ヘ`;)ウーム…情けない。

TCP周りは、ちゃんと勉強しないと駄目ですな。

mongodb-erlang + cowboy 情報なさ過ぎ

題名の通り。

不人気言語は分かるけど、海外のサイトでも見つからんとか、どうなってんの。

と言うことで、いろいろ分かった備忘録。

まずは、Erlangとmongodbのドライバは、今の所mongodb-erlangがグーグル様での人気上位らしい。
https://github.com/comtihon/mongodb-erlang

その他もあって、嘗て、mongopoolを使っていたのだけれど、更新をやってないらしく、諦める。
https://github.com/hachreak/mongopool

後者は、SQLのJoinぽい事が簡単にできた記憶があるのだが、仕方ない。

そして、Google様ご推奨の方はというと、これまたReadmeがしょぼくて、上手く動かない。取り敢えず、以下のようにしないと動かない。

	MongoConfig = [
		{auth_source, <<"test">>},   %% ソースを見るとこれがdatabase
		{database, <<"test">>},		 %% ← ソースだとadminに固定?
		{login, <<"mongo_user">>},
		{password, <<"password">>},
		{w_mode, safe},
		{host, "host_name"},
		{port, 27017}
	],

    {ok, Connection} = mc_worker_api:connect(MongoConfig), 
    Collection = <<"users">>, 
	Selection = {},
	{ok, Userdata} = mc_worker_api:find(Connection, Collection, Selection), 
	Result = mc_cursor:rest(Userdata), 
	mc_cursor:close(Userdata), 
	io:format(" users data ~p ~n", [Result]),

auth_sourceって何よ!酷いよ。

次に、mongopool見たいな使い方だけど、Readmeを読むとmongocというライブラリを使えと来ている。素直に従うと、ちっとも動かない。結局以下のようにしないと、動かなかった。

	Seeds = {single, "hostname:27017"},                                                                            
	Options =  [{name, mongopool}, {register, mongotopology}, {pool_size, 2},{rp_mode, primary}, {rp_tags, [{tag,1}]}],
	WorkerOptions = [                                                                                                  
 		{auth_source, <<"test">>}, %% ソースを見るとこれがdatabase                                                        
 		{database, <<"test">>},		 %% 将来切り替わるはず(今は、auth_source)                                             
		{login, <<"mongo_user">>},
		{password, <<"password">>},
		{w_mode, safe}                                                                                                    
	],                                                                                                                 
                                                                                                                   
	{ok, Topology} = mongoc:connect(Seeds, Options, WorkerOptions),

        Collection = <<"users">>,
	Selection = #{},
	Projector = #{},

	{ok, Userdata} = mongo_api:find(Topology, Collection, Selection, Projector), 
	Result = mc_cursor:rest(Userdata), 
	mc_cursor:close(Userdata), 
	io:format(" users data ~p ~n", [Result]),

Seedsは、Readmeだと複数設定しか書いていない。また、リストの方を一つにしても動かない。

mongoc:connectじゃないとgen_serverが起動しない。mongo_api:connectは罠?

mongo_api:findは、アリティが4しかない。最後の引数の説明が何処にもない。何これ?取り敢えず、エラーメッセージからマップ型と判断されたので、それをセット。何コレ?

Optionでnameを使っているが、何処で使うのか不明。Topologyと言う変数には、Pidが帰ってくるが、コレを保持しないとcowboyで使えない。何コレ。

erlydtl コンパイル erlydtl_preparser.hrl: no such file or directory

Procketの話題は、また別の機会に。

erlydtlってのは、Django風のビューテンプレートって事らしい。

https://github.com/erlydtl/erlydtl

ErlyDTL compiles Django Template Language to Erlang bytecode.

と書いているが、実は、以前に使った事あり。しかし、どうしたことか、rebar.configに書いただけだと、コンパイルが通らない。

ちなみにHexにあるのが、以下のような簡単な記述

{erl_opts, [debug_info]}.
{deps, [
    :
	{erlydtl, "0.12.1"},
    :

だけど、これじゃコンパイルエラーがでる。

_build/default/plugins/erlydtl/src/include/erlydtl_preparser.hrl: no such file or directory
===> Compiling _build/default/plugins/erlydtl/src/erlydtl_parser.yrl failed

結論から言うと、src/include/erlydtl_parser.yrl を作り、以下のページからソースをコピペする。

https://github.com/erlydtl/erlydtl/blob/master/include/erlydtl_preparser.hrl

なんでやろ?issueにも上がってないし、あっしの特有の問題でしょうかね。

Procket エコーサンプル 動いた でも、これじゃ駄目

この内容は、実は、コンパイルが通った次の日に書いたもの。
なかなか、順風満帆な書きっぷりだが、実は、このサンプルは、将来に渡って使えないサンプルになります。
事前に知っていて、直ぐに解決できるわ!フフン♪とか思っていたのですが、そんなに甘くはなかったのでした。


ErlangでProcketを使っているのは、以下のブログがあったから

gen_udp/tcp:send がボトルネックなときにやること

さて、昼飯食ってウトウトしつつ、以下のサンプルを転記でて動かす。

https://github.com/msantos/procket/blob/master/examples/echo.erl

ここで、問題が発生する。基本通り、Supervisor経由で起動すると、gen_udp:openでコケてしまう。エラーログも、crash reportも何を訴えているのか異次元の主張。仕方無くググってみるが、これまたGoogle先生が無言に。

仕方無いので、shellから直接、コマンド叩いて起動する。

すんなり起動。

・・・・・アレ?

これ、どうやってテストすんの?telnetできんの?最近調子が悪いGoogle先生に再び質問すると、ncとかいうツールを紹介される。

・・・・同じ端末だと、ポート競合するでしょ!

と言うことで、数ヶ月ぶりにFusionのLinuxを起動。

ncコマンドなんて入ってねー。

と言うことで以下のHPを参考にncを導入。

yum で CentOS に nc(netcat) をさくっとインストールする手順

それじゃ、遠慮無くコマンドを入力して、エコーチャットをしてみると、おお、出来るじゃないですか。と言うことで第一段階はクリア?と言うことで。

Procket コンパイルできた 自己解決

仕事中に、こそこそGoogle先生に聞いてみる。

兎に角Procketのインストール関連の話が出てこない。仕方無いので、エラーログでGoogle先生に問い合わせる。すると、次のページにぶち当たる。

Unable to compile on OS X El Captain 10.11.6 #1531

Makefileの中身を変えろって事らしい。んで、今し方中身を確認。

UNAME_SYS := $(shell uname -s)
ifeq ($(UNAME_SYS), Darwin)
	CC ?= cc
	CFLAGS ?= -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
	CXXFLAGS ?= -O3 -arch x86_64 -finline-functions -Wall
	LDFLAGS ?= -arch x86_64 -flat_namespace -undefined suppress

さっきのページそのまま。テンプレなんですかな。

UNAME_SYS := $(shell uname -s)
ifeq ($(UNAME_SYS), Darwin)
	CC ?= cc
	CFLAGS += -O3 -std=c99 -arch x86_64 -finline-functions -Wall -Wmissing-prototypes
	CXXFLAGS += -O3 -arch x86_64 -finline-functions -Wall
	LDFLAGS += -arch x86_64 -flat_namespace -undefined suppress

そのまま?を+にする。

$ rebar3 shell
===> Verifying dependencies...
===> Compiling procket
/Applications/Xcode.app/Contents/Developer/usr/bin/make -f /Users/<user_name>/<project_name>/erlang/nanisyon/_build/default/lib/procket/c_src/Makefile.ancillary
make[1]: Nothing to be done for `all'.
cc -m64  -g -Wall -o /Users/<user_name>/<project_name>/erlang/nanisyon/_build/default/lib/procket/priv/procket -L/Users/<user_name>/<project_name>/erlang/nanisyon/_build/default/lib/procket/c_src procket_cmd.c -lancillary
cc /Users/<user_name>/<project_name>/erlang/nanisyon/_build/default/lib/procket/c_src/procket.o -L/usr/local/opt/openssl/lib -arch x86_64 -flat_namespace -undefined suppress -shared -L/Users/<user_name>/<project_name>/erlang/nanisyon/_build/default/lib/procket/c_src -lancillary -L /Users/<user_name>/kerl/installs/21.1/lib/erl_interface-3.10.4/lib -lerl_interface -lei -o /Users/<user_name>/<project_name>/erlang/nanisyon/_build/default/lib/procket/c_src/../priv/procket.so
===> Compiling jsone
===> Compiling nanisyon
Erlang/OTP 21 [erts-10.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1]

Eshell V10.1  (abort with ^G)

あっさり、出来ちゃいマスタ。

XCode疑って済みません。本当に(o_ _)o

結局64bitのライブラリ?オブジェクト?が読み込めない?or見つからないというエラーなんだろうかね。

Procket コンパイルできねぇ 俺 困憊る

一通り、広く浅く、ネットワーク周りの知識を漁ったので、UDPを使った、デスクトップチャットでも作ろうかと考える。ここ最近、本ばかり読んで頭でっかち、いざ手を動かそうとすると、それまで出来ていた事が、すっぽり抜けて、なかなか前に進めない。とは言え、まずは、開発環境を整える事とした。

サーバ側は、勿論Erlangでやってみるぞ、コノヤローと一人いきんで、rebar3をアップデート、さらに、Erlangの21.1を入れておく。久々のkerlだが、勿論、覚えているわけが無く、昔のログを見ながら何とか成功。備忘録最高。

さて、取り敢えず、プロジェクトが無いと始まらないので、適当な名前でプロジェクトを作成。ここまでは、何とかなった。

問題は、ここから。rebar.configの中を以下のように編集。

{deps, [
	{jsone,   {git, "https://github.com/sile/jsone.git", {tag, "master"}}},
	{procket, "0.9.3"}
]}.
$ rebar3 shell
===> Verifying dependencies...
===> Compiling procket
/Applications/Xcode.app/Contents/Developer/usr/bin/make -f /Users/<user_name>/<project_name>/_build/default/lib/procket/c_src/Makefile.ancillary
make[1]: Nothing to be done for `all'.
cc -m64  -g -Wall -o /Users/<user_name>/<project_name>/_build/default/lib/procket/priv/procket -L/Users/<user_name>/<project_name>/_build/default/lib/procket/c_src procket_cmd.c -lancillary
cc /Users/<user_name>/<project_name>/_build/default/lib/procket/c_src/procket.o -L/usr/local/opt/openssl/lib -shared -L/Users/<user_name>/<project_name>/_build/default/lib/procket/c_src -lancillary -L /Users/<user_name>/kerl/installs/21.1/lib/erl_interface-3.10.4/lib -lerl_interface -lei -o /Users/<user_name>/<project_name>/_build/default/lib/procket/c_src/../priv/procket.so
Undefined symbols for architecture x86_64:
  "_enif_alloc_binary", referenced from:
      _nif_accept in procket.o
      _nif_read in procket.o
      _nif_ioctl in procket.o

〜 略 〜
      ...
  "_enif_release_binary", referenced from:
      _nif_read in procket.o
      _nif_recvmsg in procket.o
      _nif_recvfrom in procket.o
  "_enif_release_resource", referenced from:
      _nif_alloc in procket.o
  "_erl_errno_id", referenced from:
      _nif_fdrecv in procket.o
      _nif_close in procket.o
      _nif_accept in procket.o
      _nif_bind in procket.o
      _nif_connect in procket.o
      _nif_getsockname in procket.o
      _nif_getsockopt in procket.o
      ...

ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [/Users/<user_name>/<project_name>/_build/default/lib/procket/c_src/../priv/procket.so] Error 1
===> Hook for compile failed!

ちょっと、何コレ_| ̄|○

Google先生も、何も答えてくれない。何故、どうして、こうなる。

怪しいのは、XCodeのmake当たりか?最近XCodeのバージョン上がったし、疑わざるを得ない。

誰かぁ!ご存じの方いたら、優しく教えて下さい。

macOS: Mojave 10.14
XCode 10.1
rebar3 3.7.0-rc2+build.4175.ref83d01b52 on Erlang/OTP 21 Erts 10.1
erlang 21.1

ちなみに、jsoneは、「入るかな?」のお試しです。此方は、問題なく入るのに。

英語が分かれば、直でissue出したいけど、無理っす。

Stun Turn と諸々

あ〜またもや数ヶ月。しかし、この間劇的な進展があったので、備忘録も含めて更新。

まず、Erlang周りが大分解決。勿論、オールクリアなんて事は、ありません。

・Socket通信 TCP通信
https://www.ymotongpoo.com/works/lyse-ja/ja/26_buckets_of_sockets.html#tcp
作者、訳とも凡人には、わかりにくい校正ながら、サンプルで何度も、反芻して何とか、いや何となく解決。
gen_tcpからgen_serverに発展とか、素人には、ウルトラ難しい。

【参考】https://dmathieu.com/articles/development/erlang-tcp-server/
つーか、これなかったら、全く分からんかった。

これから、Swift4へつないで、チャットサンプル作成。こちらは、また纏めて備忘録作成。

・Socket通信 udp通信
何となく、分かった気がしたけど、NAT越えをしないと、普通は使えない事が分かる。しらんかったのか!と驚く事なかれ。しらんかったのです。この年で、ちょっとだけ、脳に皺増えました。ありがとうございます。

WebRTC https://gist.github.com/voluntas/975bfa230e513d146965

ベクトルがぶっ飛び過ぎ!普通にNAT越え調べたら、こればっかり。

本買った。時雨堂さんって凄いのね。尊敬します。時雨堂さんご推奨本+α

WebRTC ブラウザベースのP2P技術

WebRTC ブラウザベースのP2P技術

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化

ハイパフォーマンス ブラウザネットワーキング ―ネットワークアプリケーションのためのパフォーマンス最適化

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

Real World HTTP ―歴史とコードに学ぶインターネットとウェブ技術

高度過ぎて、「なるほど分からん状態」

但し、StunとTurnは、Erlangで組んであるものを発見。

●STUN and TURN library for Erlang / Elixir
https://github.com/processone/stun

rebar3でも動かせた。

あとは、コレをどうやって通信で使えば良いのか、サンプルを探しております。ヘッダーだけ、stunで取得したものを織り込んで、あとは、そのまま送りつけるの?カスタムヘッダーが云々あるけど、指定するんだろうかね。

(´ヘ`;)ウーム… 使いこなすには、まだ長い道のりが・・・。

●WebRTC
lambdaclass/webrtc-server
https://github.com/lambdaclass/webrtc-server

How to set up MongooseICE (ICE/TURN/STUN server)
https://www.erlang-solutions.com/blog/how-to-set-up-mongooseice-ice-turn-stun-server.html

単純にWebRTCを実現するなら、上記の物でも良い?のかも。

したのは、有名なものらしい。