OSX El Capitanにrbenvで1.8.7-p375を入れる
もういい加減にしたいと思っている1.8.7なのですが、 残っているところがある以上、こちらでも開発環境を用意しなければならないのです。
rbenv install 2.2.3
とかは問題なくインストールできました。しかし、
rbenv install 1.8.7-p375
とやってみたのですが、エラーが出ます。
ERROR: This package must be compiled with GCC, but ruby-build couldn't find a suitable `gcc` executable on your system. Please install GCC and try again. DETAILS: Apple no longer includes the official GCC compiler with Xcode as of version 4.2. Instead, the `gcc` executable is a symlink to `llvm-gcc`, a modified version of GCC which outputs LLVM bytecode. For most programs the `llvm-gcc` compiler works fine. However, versions of Ruby older than 1.9.3-p125 are incompatible with `llvm-gcc`. To build older versions of Ruby you must have the official GCC compiler installed on your system. TO FIX THE PROBLEM: Install Homebrew's apple-gcc42 package with this command: brew tap homebrew/dupes ; brew install apple-gcc42 You will need to install the official GCC compiler to build older versions of Ruby even if you have installed Apple's Command Line Tools for Xcode package. The Command Line Tools for Xcode package only includes `llvm-gcc`. BUILD FAILED (OS X 10.11 using ruby-build 20150818-4-g8d6ff29)
こんなエラーが出ます。エラーメッセージのとおりにやってみたのですが、 全然ダメでした。仕方ないのでビルドディレクトリに移動してみて、 ./configureをやったらあっさり通ります。 なんだ、ruby-buildの問題か。というわけで、デバッグをしはじめました。 ちょっとだけ追ってみたら、require_gccのあたりのようで、 gccのチェックをしている模様。
--- a/share/ruby-build/1.8.7-p375 +++ b/share/ruby-build/1.8.7-p375 @@ -1,3 +1,3 @@ -require_gcc +# require_gcc
これであっさり通るようになりました。 ちゃんと直すのは面倒だなぁ。っというわけで誰かお願いします。 bashの動きを調べるのめんどい。
あなたならどうするこのルーター設定
とあるシステムと接続するにあたって、 サービス元のIPアドレス 192.168.10.1/24 持ち込みルータのIPアドレス 192.168.20.1/24 サービス先のIPアドレス 192.168.30.1/24 ポート番号10000 ってな感じで、全部サブネットと違っていて、ポートが指定されてしまっている。 NATで変換したいんだけど、間に192.168.30.0/24のネットワークを 構築する余地もない。
さてどうする?
解1. がんばってLANを構築し直して、192.168.30.0/24のネットワークにしてしまう。
解2. 静的ルーティングで192.168.100.2のサーバに192.168.30.0/24のルートを向けて、ループバックに192.168.30.2を指定する。仕方ないのでポートはそのまま使う。
どちらの案もNAT使っていないんだけど、通過するだけのパケットのIPとかポートを 捻じ曲げる方法があるって人は教えて下さい。 もうわからん。
追記
lan1にサービス先のサブネットを振り、Static NATをすることで実現できました。 試していないのですが、ポートとIPを組み合わせてmasquaradeする方法でもいけるでしょう。
ip lan1 address 192.168.20.1/24 ip lan1 secondary address 192.168.30.2/24 ip lan1 nat descriptor 1 nat descriptor type 1 nat nat descriptor address outer 1 192.168.30.1-192.168.30.254 nat descriptor address inner 1 192.168.20.1-192.168.20.254 nat descriptor static 1 1 192.168.30.1=192.168.100.1 254
16進数が文字列になっちゃっているものを配列にしたい
お題 "FF2E0A" => [255, 46, 10] と変換したい
16進数が文字列として入っている。
"FF2E0A".scan(/.{2}/).map{|c|Integer("0x#{c}")}
これだとやはり長い。
["FF2E0A"].pack("H*").bytes
これがやはり最強だな。knuさんに教えてもらったけど、考えてもすぐには出てこない。
["FF2E0A"].pack("H*")
これだけだと文字列になりますので、これはこれで使えます。
pack / unpack は最強。
C言語の外部コマンドへの入出力がよくわからない
とりあえず、現状で必要なのはgzip圧縮されたデータを受信して、展開したいだけ。 あっさりzlibライブラリで解決するかと思いきや、 zlibを読んだ感じでは、gzipはファイル化しなけりゃならないっぽい。 ファイル化とか面倒だと思ってgunzip -cに吸い込ませた結果を 読みこめばいいかとRubyのOpen3感覚で思っていたらハマってしまった。
とりあえず、やりたかったことをRubyで書いた。
gzipdata = open(ARGV[0], "rb").read # やりたいことは、gzip圧縮されたデータを展開したいだけ pipe = IO.popen("gunzip -c", "r+") pipe.write gzipdata pipe.close_write data = pipe.read pipe.close # 結果の出力 result_file = open("result.jpg", "wb") result_file.write data result_file.close
これ、C言語でやろうとするとめんどくさい。 ネットなどで検索すると、pipeを作ってforkしろと書いてある。 プロセス複製とかしなきゃならんのか〜とか思ってちょっと萎える。
もう、gzipデータをRubyプログラムに丸っとパイプかドメインソケットで渡して そっちで処理してくれというプログラムにしちまうか。。
というわけで、誰か偉い人教えて下さい。
- Cでforkせずともできるものなのか
- Cではforkするのが常識なのか
- そもそも何か間違っているのか
- zlibでファイル作らずともあっさり出来るよ〜みたいな情報
もうわからん。
Rubyでサーバを作ってクライアントにデータを配信 vol.6
vol.5のように時間がかかる処理があると待たされてしますので、 それを解決したコードが次のコードです。
require "socket" port = if ARGV[0] then ARGV[0] else 'echo' end gate = TCPServer.open(port) sockets = [gate, STDIN] clients = [] loop do r_sockets = IO.select(sockets+clients)[0] r_sockets.each do |socket| case socket when STDIN str = socket.gets threads = [] clients.each do |client| threads << Thread.new do client.puts str.upcase sleep 2 end end threads.each{|t|t.join} when TCPServer client = socket.accept clients << client p clients when TCPSocket unless socket.eof? str=socket.gets socket.puts str.upcase else socket.close clients.delete(socket) p clients end end end end gate.close
スレッドを使って次々と並列して処理を開始し、最後にjoinで処理が全て終了するのを待ちます。
とりあえずRubyではここまで検証をしたかったので一旦終了。
Rubyでサーバを作ってクライアントにデータを配信 vol.5
vol.4のプログラムはclientsにひとつずつ配信しています。 一瞬で終わるならいいのですが、ネットワークなんて遅延しまくりなので、 あまりよろしくありません。一度に配信処理をしたいものです。 試しに2秒遅延を入れてみると、こうなります。
require "socket" port = if ARGV[0] then ARGV[0] else 'echo' end gate = TCPServer.open(port) sockets = [gate, STDIN] clients = [] loop do r_sockets = IO.select(sockets+clients)[0] r_sockets.each do |socket| case socket when STDIN str = socket.gets clients.each do |client| client.puts str.upcase sleep 2 end when TCPServer client = socket.accept clients << client p clients when TCPSocket unless socket.eof? str=socket.gets socket.puts str.upcase else socket.close clients.delete(socket) p clients end end end end gate.close
このくらいレスポンスが悪いと、ああ、なんとかしなきゃならないなと思いますね。
Rubyでサーバを作ってクライアントにデータを配信 vol.4
スレッドなどでそれぞれ待ち受けるという手もありますが、 IOの入出力を待つ手段としては一般的ではないようです。 IOの動きを監視して待ち受け、動きがあったら場合分けをして 処理をするのが一般的なようです。 これをReactorパターンといいます。 IO.selectで配列を引数に入れると、 引数で入れたものに動きがあるまで待ち続けます。 動きがあると、次のステップに進むので、そこで場合分けをして処理をします。
require "socket" port = if ARGV[0] then ARGV[0] else 'echo' end gate = TCPServer.open(port) sockets = [gate, STDIN] clients = [] loop do r_sockets = IO.select(sockets+clients)[0] r_sockets.each do |socket| case socket when STDIN str = socket.gets clients.each do |client| client.puts str.upcase end when TCPServer client = socket.accept clients << client p clients when TCPSocket unless socket.eof? str=socket.gets socket.puts str.upcase else socket.close clients.delete(socket) p clients end end end end gate.close
いくつも同時に接続して、配信可能です。