Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Ruby 프로젝트 아이디어:나만의 Linux 도구 빌드

함께 프로젝트를 만들어요!

ps와 같은 Linux 도구 , top &netstat 훌륭합니다.

시스템 상태에 대한 많은 정보를 제공합니다.

  • 하지만 어떻게 작동합니까?
  • 모든 정보는 어디에서 얻나요?
  • 이를 사용하여 자체 도구를 구축하려면 어떻게 해야 하나요?

이 게시물에서는 세 가지 인기 있는 Linux 도구를 함께 다시 만들 것입니다.

2x1 식사를 하고 Ruby 트릭을 배우고 동시에 유용한 Linux 지식을 얻을 수 있습니다! 🙂

상태 정보 찾기

이제 이 모든 도구가 정보를 찾는 위치에 대한 질문에 답해 보겠습니다.

답은 proc 파일 시스템에 있습니다!

/proc 내부를 보면 디렉토리는 컴퓨터의 다른 디렉토리와 마찬가지로 많은 디렉토리 및 파일처럼 보입니다.

이것은 실제 파일이 아니며 Linux 커널이 사용자에게 데이터를 노출하는 방법일 뿐입니다.

일반 파일처럼 취급할 수 있어 특별한 도구 없이도 읽을 수 있어 매우 편리합니다.

Linux 세계에서는 많은 것들이 이와 같이 작동합니다.

다른 예제를 보고 싶다면 /dev를 살펴보세요. 디렉토리.

이제 우리가 무엇을 다루고 있는지 이해했으므로 /proc의 내용을 살펴보겠습니다. 디렉토리...

110104105111101511469114741155211655

이것은 작은 샘플이지만 패턴을 빠르게 알아차릴 수 있습니다.

그 숫자가 모두 무엇입니까?

이것이 PID(프로세스 ID)라는 것이 밝혀졌습니다.

모든 항목에는 특정 프로세스에 대한 정보가 포함되어 있습니다.

ps를 실행하면 모든 프로세스에 PID가 어떻게 연결되어 있는지 확인할 수 있습니다.

PID TTY 시간 CMD15952 pts/5 00:00:00 ps22698 pts/5 00:00:01 bash

이것으로부터 우리는 ps가 하는 것이 /proc를 반복한다는 것을 추론할 수 있습니다. 디렉토리 및 찾은 정보를 인쇄합니다.

번호가 매겨진 디렉토리 중 하나에 무엇이 들어 있는지 살펴보겠습니다.

attrautogroupauxvcgroupclear_refscmdlinecommcpusetcwdenvironexefd

공간을 절약하기 위한 샘플일 뿐이지만 전체 목록을 살펴보시기 바랍니다.

흥미로운 항목이 있습니다. :

항목 설명
통신 프로그램 이름
cmdline 이 프로세스를 시작하는 데 사용되는 명령
환경 이 프로세스가 시작된 환경 변수
상태 프로세스 상태(실행 중, 절전 모드...) 및 메모리 사용량
fd 파일 설명자를 포함하는 디렉토리(열린 파일, 소켓…)

이제 우리는 이것을 알았으므로 몇 가지 도구를 작성할 수 있어야 합니다!

실행 중인 프로그램을 나열하는 방법

/proc 아래의 모든 디렉토리 목록을 가져오는 것으로 시작하겠습니다. .

Dir를 사용하여 이 작업을 수행할 수 있습니다. 수업.

:

Dir.glob("/proc/[0-9]*")

숫자 범위를 사용한 방법에 주목하세요. 그 이유는 /proc 아래에 다른 파일이 있기 때문입니다. 지금은 신경 쓰지 않고 번호가 매겨진 디렉토리만 원합니다.

이제 이 목록을 반복하고 PID가 있는 열과 프로그램 이름이 있는 열 두 개를 인쇄할 수 있습니다.

:

pids =Dir.glob("/proc/[0-9]*")puts "PID\tCMD"puts "-" * 15pids.each do |pid| cmd =File.read(pid + "/comm") pid =pid.scan(/\d+/).first "#{pid}\t#{cmd}"end

이것이 출력입니다 :

PID CMD---------------1 systemd2 kthreadd3 ksoftirqd/05 kworker/07 마이그레이션/08 rcu_preempt9 rcu_bh10 rcu_sched

안녕하세요, 방금 ps를 만든 것 같습니다. ! 예, 원본의 모든 멋진 옵션을 지원하지는 않지만 우리가 뭔가를 만들었습니다.

누가 듣고 있습니까?

netstat를 복제해 봅시다. 이제 출력은 다음과 같습니다(-ant 사용). 플래그로).

활성 인터넷 연결(서버 및 설정됨)Proto Recv-Q Send-Q 로컬 주소 외부 주소 상태 tcp 0 0 127.0.0.1:5432 0.0.0.0:* LISTEN tcp 0 0 192.168.1.82:39530 9122.15. 설립

이 정보는 어디에서 찾을 수 있습니까? "/proc 내부 " 네가 옳아! 보다 구체적으로 /proc/net/tcp에서 찾을 수 있습니다. .

하지만 약간의 문제가 있습니다. 이것은 netstat처럼 보이지 않습니다. 출력!

 0 :0100007F :1538 00000000 :0000 0A 00000000 :00000000 00 :0000000000000000000010101010161 :2E58A8C0 :9A6A 9FBB0EB9 :0016 01 00000000 :00000000 00 :000000000000000000000000 0000000000000000000000000 000 

이것이 의미하는 바는 정규 표현식으로 일부 구문 분석을 수행해야 한다는 것입니다. 지금은 로컬 주소와 상태에 대해서만 신경쓰자.

여기에 내가 생각해낸 정규식이 있습니다. :

LINE_REGEX =/\s+\d+:(?\w+):(?\w+) \w+:\w+ (?\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 # 16진수를 일반으로 변환 IP 표기법 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 # 이것에 대해 너무 걱정하지 마십시오. 그것은 이진 수학입니다. def decimal_to_ip(십진수) ip =[] ip <<(십진수>> 24 &0xFF) ip <<(십진수>> 16 &0xFF) ip <<(십진수>> 8 &0xFF) ip <<(십진수 &0xFF) ip.join(".") 끝

남은 것은 결과를 예쁜 표 형식으로 인쇄하는 것뿐입니다.

'table_print'tp 연결 필요

예시 출력 :

상태 | LOCAL_PORT | LOCAL_ADDR ------------|------------|----------------듣기 | 5432 | 127.0.0.1 설립 | 39530 | 192.168.88.46

예, 이 보석은 훌륭합니다!

방금 찾았고 ljust로 더듬거리지 않아도 될 것 같습니다. / rjust 다시 🙂

내 포트 사용을 중지하십시오!

이 메시지를 본 적이 있습니까?

이미 사용 중인 주소 - "localhost" 포트 5000에 대한 bind(2)

음...

어떤 프로그램이 그 포트를 사용하고 있는지 궁금합니다.

알아보자 :

fuser -n tcp -v 5000PORT 사용자 PID 액세스 CMD5000/tcp rubyguides 30893 F.... nc

아, 범인이 있습니다!

이제 이 프로그램이 실행되는 것을 원하지 않으면 중지할 수 있습니다. 그러면 포트가 해제됩니다. "퓨저" 프로그램은 누가 이 포트를 사용하고 있는지 어떻게 알아냈습니까?

짐작하셨군요!

/proc 다시 파일 시스템.

사실, 그것은 우리가 이미 다룬 두 가지를 결합합니다:프로세스 목록을 살펴보고 /proc/net/tcp에서 활성 연결 읽기 .

한 단계만 더하면 됩니다. :

열린 포트 정보를 PID와 일치시키는 방법을 찾으십시오.

/proc/net/tcp에서 얻을 수 있는 TCP 데이터를 보면 , PID가 없습니다. 하지만 inode 번호를 사용할 수 있습니다.

<블록 인용>

"inode는 파일 시스템 개체를 나타내는 데 사용되는 데이터 구조입니다." – 위키피디아

inode를 사용하여 일치하는 프로세스를 찾는 방법은 무엇입니까? fd 아래를 보면 우리가 알고 있는 프로세스의 디렉토리에 열린 포트가 있는 경우 다음과 같은 행을 찾을 수 있습니다.

/proc/3295/fd/5 -> 소켓:[12345]

대괄호 사이의 숫자는 inode 번호입니다. 이제 모든 파일을 반복하면 일치하는 프로세스를 찾을 수 있습니다.

여기에 한 가지 방법이 있습니다. :

x =Dir.glob("/proc/[0-9]*/fd/*").find do |fd| 파일.readlink(fd).include? "소켓:[#{소켓_아이노드}]" 구출 nilendpid =x.scan(/\d+/).firstname =File.readlink("/proc/#{pid}/exe")puts "포트 #{hex_port.to_i( 16)} #{name}(#{pid})에서 사용 중"

출력 예:

/usr/bin/postgres(474)에서 사용 중인 포트 5432

이 코드를 루트 또는 프로세스 소유자로 실행해야 합니다.

그렇지 않으면 /proc 내부의 프로세스 세부 정보를 읽을 수 없습니다. .

결론

이 게시물에서는 Linux가 가상 /proc를 통해 많은 데이터를 노출한다는 것을 배웠습니다. 파일 시스템. 또한 /proc 아래의 데이터를 사용하여 ps, netstat 및 fuser와 같은 인기 있는 Linux 도구를 다시 만드는 방법도 배웠습니다. .

다음 게시물을 놓치지 않도록 아래 뉴스레터 구독을 잊지 마세요. 🙂