Rubyプロジェクトのアイデア:独自のLinuxツールを構築する
一緒にプロジェクトを作りましょう!
ps
などのLinuxツール 、top
&netstat
素晴らしいです。
システムで何が起こっているかについて多くの情報を提供します。
- しかし、それらはどのように機能しますか?
- 彼らはどこからすべての情報を入手しますか?
- これを使用して独自のツールを構築するにはどうすればよいですか?
この投稿では、3つの人気のあるLinuxツールを一緒に再作成します。
2×1の食事を取り、Rubyのトリックを学び、同時にLinuxの有用な知識を習得します。 🙂
ステータス情報の検索
それでは、これらすべてのツールが情報をどこで見つけるかという質問に答えてみましょう。
答えはprocファイルシステムにあります!
/proc
の内部を見ると ディレクトリそれは、コンピュータ上の他のディレクトリと同じように、一連のディレクトリとファイルのように見えます。
これらは実際のファイルではなく、Linuxカーネルがユーザーにデータを公開するための単なる方法です。
通常のファイルと同じように扱うことができるため、特別なツールなしで読み取ることができるため、非常に便利です。
Linuxの世界では、多くのことがこのように機能します。
別の例を見たい場合は、/dev
を見てください。 ディレクトリ。
何を扱っているかがわかったので、/proc
の内容を見てみましょう。 ディレクトリ…
1 10 104 105 11 11015 11469 11474 11552 11655
これはほんの小さなサンプルですが、パターンにすぐに気付くことができます。
これらの数字は何ですか?
そうですね、これらはPID(プロセスID)であることがわかりました。
すべてのエントリには、特定のプロセスに関する情報が含まれています。
ps
を実行する場合 すべてのプロセスにPIDが関連付けられていることがわかります:
PID TTY TIME CMD 15952 pts/5 00:00:00 ps 22698 pts/5 00:00:01 bash
このことから、psが行うことは/proc
を反復するだけであると推測できます。 ディレクトリを作成し、見つかった情報を印刷します。
これらの番号が付けられたディレクトリの1つに何が入っているか見てみましょう:
attr autogroup auxv cgroup clear_refs cmdline comm cpuset cwd environ exe fd
これはスペースを節約するための単なるサンプルですが、完全なリストを確認することをお勧めします。
ここにいくつかの興味深いエントリがあります :
comm | |
コマンドライン | |
プロセスステータス(実行中、スリープ中…)とメモリ使用量 | |
fd | ファイル記述子(開いているファイル、ソケットなど)を含むディレクトリ |
これがわかったので、いくつかのツールを書き始めることができるはずです!
実行中のプログラムを一覧表示する方法
/proc
の下にあるすべてのディレクトリのリストを取得することから始めましょう 。
Dir
を使用してこれを行うことができます クラス。
例 :
Dir.glob("/proc/[0-9]*")
数値範囲をどのように使用したかに注意してください。その理由は、/proc
の下に他のファイルがあるためです。 今は気にしないので、番号の付いたディレクトリだけが必要です。
これで、このリストを繰り返し処理して、2つの列を出力できます。1つはPIDで、もう1つはプログラム名です。
例 :
pids = Dir.glob("/proc/[0-9]*") puts "PID\tCMD" puts "-" * 15 pids.each do |pid| cmd = File.read(pid + "/comm") pid = pid.scan(/\d+/).first puts "#{pid}\t#{cmd}" end
これが出力です :
PID CMD --------------- 1 systemd 2 kthreadd 3 ksoftirqd/0 5 kworker/0 7 migration/0 8 rcu_preempt 9 rcu_bh 10 rcu_sched
ねえ、ps
を作ったようです !ええ、それはオリジナルからのすべての派手なオプションをサポートしていませんが、私たちは何かを機能させました。
誰が聞いていますか?
netstat
を複製してみましょう これで、出力は次のようになります(-ant
を使用) フラグとして)。
Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN tcp 0 0 192.168.1.82:39530 182.14.172.159:22 ESTABLISHED
この情報はどこにありますか? 「/proc
の内部」と言った場合 " あなたが正しい!具体的には、/proc/net/tcp
にあります。 。
ただし、少し問題があります。これはnetstat
のようには見えません。 出力!
0: 0100007F:1538 00000000:0000 0A 00000000:00000000 00:00000000 00000000 1001 0 9216 1: 2E58A8C0:9A6A 9FBB0EB9:0016 01 00000000:00000000 00:00000000 00000000 1000 0 258603
これが意味するのは、正規表現を使用して解析を行う必要があるということです。とりあえず、ローカルアドレスとステータスについて心配しましょう。
これが私が思いついた正規表現です :
LINE_REGEX = /\s+\d+: (?<local_addr>\w+):(?<local_port>\w+) \w+:\w+ (?<status>\w+)/
これにより、10進数に変換する必要のある16進値が得られます。これを行うクラスを作成しましょう。
class TCPInfo def initialize(line) @data = parse(line) end def parse(line) line.match(LINE_REGEX) end def local_port @data["local_port"].to_i(16) end # Convert hex to regular IP notation def local_addr decimal_to_ip(@data["local_addr"].to_i(16)) end STATUSES = { "0A" => "LISTENING", "01" => "ESTABLISHED", "06" => "TIME_WAIT", "08" => "CLOSE_WAIT" } def status code = @data["status"] STATUSES.fetch(code, "UNKNOWN") end # Don't worry too much about this. It's some binary math. def decimal_to_ip(decimal) ip = [] ip << (decimal >> 24 & 0xFF) ip << (decimal >> 16 & 0xFF) ip << (decimal >> 8 & 0xFF) ip << (decimal & 0xFF) ip.join(".") end end
残っているのは、結果をきれいな表形式で印刷することだけです。
require 'table_print' tp connections
出力例 :
STATUS | LOCAL_PORT | LOCAL_ADDR ------------|------------|-------------- LISTENING | 5432 | 127.0.0.1 ESTABLISHED | 39530 | 192.168.88.46
はい、この宝石は素晴らしいです!
私はそれについて見つけたばかりで、ljust
をいじくり回す必要はないようです / rjust
もう一度🙂
マイポートの使用をやめてください!
このメッセージを見たことがありますか?
Address already in use - bind(2) for "localhost" port 5000
うーん…
どのプログラムがそのポートを使用しているのだろうか。
調べてみましょう :
fuser -n tcp -v 5000 PORT USER PID ACCESS CMD 5000/tcp rubyguides 30893 F.... nc
ああ、それで私たちの犯人がいます!
これで、このプログラムを実行したくない場合は停止できます。これにより、ポートが解放されます。 「fuser」プログラムは、このポートを使用しているユーザーをどのようにして見つけましたか?
あなたはそれを推測しました!
/proc
再びファイルシステム。
実際、これはすでに説明した2つのことを組み合わせたものです。プロセスリストをウォークスルーすることと、/proc/net/tcp
からアクティブな接続を読み取ることです。 。
もう1つのステップが必要です :
開いているポート情報をPIDと一致させる方法を見つけてください。
/proc/net/tcp
から取得できるTCPデータを見ると 、PIDはありません。ただし、iノード番号を使用できます。
「iノードは、ファイルシステムオブジェクトを表すために使用されるデータ構造です。」 –ウィキペディア
iノードを使用して一致するプロセスを見つけるにはどうすればよいですか? fd
の下を見ると ポートが開いていることがわかっているプロセスのディレクトリには、次のような行があります:
/proc/3295/fd/5 -> socket:[12345]
括弧内の数字はiノード番号です。これで、すべてのファイルを反復処理するだけで、一致するプロセスが見つかります。
これを行う1つの方法があります :
x = Dir.glob("/proc/[0-9]*/fd/*").find do |fd| File.readlink(fd).include? "socket:[#{socket_inode}]" rescue nil end pid = x.scan(/\d+/).first name = File.readlink("/proc/#{pid}/exe") puts "Port #{hex_port.to_i(16)} in use by #{name} (#{pid})"で使用中
出力例:
Port 5432 in use by /usr/bin/postgres (474)
このコードはrootまたはプロセス所有者として実行する必要があることに注意してください。
そうしないと、/proc
内のプロセスの詳細を読み取ることができません。 。
結論
この投稿では、Linuxが仮想/proc
を介して大量のデータを公開することを学びました ファイルシステム。また、/proc
の下のデータを使用して、ps、netstat、fuserなどの一般的なLinuxツールを再作成する方法も学びました。 。
次の投稿を見逃さないように、以下のニュースレターを購読することを忘れないでください。 🙂
-
Rubyの関数とメソッド:独自の関数を定義する方法
Rubyメソッドとは何ですか? メソッドは、特定の目的のためにグループ化された1行または複数行のRubyコードです。 このグループ化されたコードには名前が付けられているため、コードを再度記述したり、コピーして貼り付けたりすることなく、いつでも使用できます。 メソッドの目的は次のとおりです : 情報を取得します。 オブジェクトを変更または作成します。 フィルターとフォーマットのデータ。 例1 : サイズ Arrayのメソッド オブジェクトは要素の数を示します(情報を取得します)。 例2 : pop メソッドは、配列から最後の要素を削除します(オブジェクトを変更します)。
-
SUSE Studio - 独自の Linux を作成する
SUSE Studio は、Novell が後援するサービスであり、繰り返しますが、どなたでも、ある程度の忍耐と Web ブラウザだけを使用して、openSUSE とその変種の独自のカスタム フレーバーを作成できます。すごいですね?です。 SUSE Studio は、驚異的な成功を収めた有用な Kiwi イメージング システムの次の自然なステップです。これにより、SUSE ユーザーはオペレーティング システムの独自のエディションをすばやく簡単に作成できます。 はじめに Image Creator や Product Creator などのフレンドリーなフロントエンド アプライ