Linux에서 소켓 연결 시간을 결정하는 방법


24

연결이되어 있는지 확인할 수 있습니다.

$ netstat -tn | grep "192.168.2.110"
tcp  0  0 192.168.2.100:10444  192.168.2.110:52639  ESTABLISHED

이 tcp 포트 연결이 얼마나 오래 연결되었는지 확인하는 방법이 있습니까?

(아니요, 앱 로그에 액세스 할 수 없습니다)

답변:


23

다음을 시도 할 수 있습니다.

  1. $pid-p옵션을 추가하여 프로그램 의 PID (예 :)를 얻습니다 netstat.

  2. 에서 적절한 라인 식별 /proc/net/tcp상기보고 파일 local_address및 / 또는 rem_address도 확인이 있는지 확인, (그들은 특히 IP 주소가 리틀 엔디안 바이트 순서로 표현, 진수 형식으로되어 있습니다)를 필드 st입니다 01(위해 ESTABLISHED);

  3. 관련 inode필드를 주목하십시오 (예 :) $inode.

  4. inode파일 설명자에서 해당 파일 설명자를 검색 /proc/$pid/fd하고 마지막으로 심볼릭 링크의 파일 액세스 시간을 쿼리하십시오.

    find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %t
    

위의 사항을 자동화하는 스크립트 (스텁)가 있습니다. 원격 주소가 필요하며 소켓 가동 시간 을 초 단위로 인쇄합니다 .

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}
    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")
    # get the PID of the owner process
    local pid=$(netstat -ntp 2>/dev/null | awk '$6 == "ESTABLISHED" && $5 == "'$addr:$port'"{sub("/.*", "", $7); print $7}')
    [ -z "$pid" ] && { echo 'Address does not match' 2>&1; return 1; }
    # get the inode of the socket
    local inode=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inode" ] && { echo 'Cannot lookup the socket' 2>&1; return 1; }
    # query the inode status change time
    local timestamp=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %T@)
    [ -z "$timestamp" ] && { echo 'Cannot fetch the timestamp' 2>&1; return 1; }
    # compute the time difference
    LANG=C printf '%s (%.2fs ago)\n' "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
}

(에 편집 덕분에 알렉스 에 대한 수정 )

예:

$ suptime 93.184.216.34 80
Thu Dec 24 16:22:58 CET 2015 (46.12s ago)

1
이 레시피는 연결 자체가 아닌 TCP 연결을 생성 한 프로세스 기간을 표시합니다.
myroslav

@myroslav 확실합니까? 이 Node.js 스크립트 에 대해 작동합니다 .
cYrus

Fedora 22 64 비트에서 Firefox로 열린 TCP 연결을 사용하여 새 스크립트를 테스트했는데 "업타임"숫자가 확실하지 않습니다. 새 소켓이 열리면 "랜덤"가동 시간, 일반적으로 "가장 젊은"ESTABLISHED 소켓 시간이 발생합니다.
myroslav

@myroslav 여기서 데비안 (3.16.0-4-amd64)을 사용하고 있는데,보고있는 유일한 시간은 소켓 생성과 관련하여 실제로 약 3 초 늦었다는 것입니다. 아마도 시스템에 의존하는 행동이있을 수 있습니다.
cYrus

스크립트의 경우 "$ suptime 192 : 168 : 120 : 10 6379 Traceback (가장 최근 호출) : <module> socket.error의 1 행,"<string> "파일 오류 : inet_aton에 전달 된 잘못된 IP 주소 문자열 일치하지 않음 "
Ondra Žižka

4

이 질문은 나에게 도움이되었지만 모든 HEX 물건을 피하는 lsof대신 사용 하는 것으로 나타났습니다 netstat.

${APP}user가 실행 하는 프로세스의 ${USER}경우 다음은 모든 열린 소켓을 IP 주소 $ {IP}로 반환합니다.

PEEID=$(sudo pgrep -u ${USER} ${APP}) && for i in `sudo lsof -anP -i -u logstash | grep ${IP} | awk '{print $6}'` ; do echo "${device} time" ; sudo find /proc/${PEEID}/fd -lname "socket:\[${device}\]" -printf %t 2> /dev/null  ; echo  ;  done

lsof포함되어 PID있지만 그것을 얻는 방법과 장치 번호를 잘 모르겠습니다.

이것은 Amazon Linux에서 테스트되었습니다.


3

cYrus의 스크립트가 나를 위해 일했지만 16 비트 주소에서 "L"을 제거하고 포트를 4 자리 16 진수로 만들려면 약간 수정해야했습니다.

--- suptime.orig    2015-08-20 15:46:12.896652464 +0200
+++ suptime 2015-08-20 15:47:48.560074728 +0200
@@ -7,8 +7,8 @@
     hex_addr=$(python -c "
 import socket, struct;
 print hex(struct.unpack('<L',
-socket.inet_aton('$addr'))[0])[2:].upper().zfill(8)")
-    hex_port=$(python -c "print hex($port)[2:].upper()")
+socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8)")
+    hex_port=$(python -c "print hex($port)[2:].upper().zfill(4)")
     inode=$(awk '$3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
     time=$(find /proc/$pid/fd -lname "socket:\[$inode\]" -printf %A@)
     LANG=C printf '%.2fs' $(bc <<<"$(date +%s.%N) - $time")

1

어때요?

lsof -t -i @ 192.168.2.110 | xargs ps -fp

"ps"명령을 다음과 같이 -o를 사용하여 pid 및 시작 시간을 갖도록 조정할 수도 있습니다.

lsof -t -i @ 192.168.2.110 | xargs ps --no-headers -o'pid, start '-p

물론 이것은 프로세스가 시작되었을 때 소켓이 시작되었다고 가정합니다.


소켓을 연 프로세스가 얼마나 오래 진행되었는지 보여줍니다. 항상 실행되는 프로세스가 있고 네트워크 연결이 끊어진 경우 이러한 값은 매우 다릅니다. 노력 +1
hidralisk

1

cYrus의 답변으로 유지되는 스크립트에 감사드립니다. 중복 된 인쇄에 문제가 있었을 것입니다. 아마 다른 PID에서 제공된 주소로 많은 연결이있을 수 있기 때문에 각 출력 라인에 PID를 인쇄하는 개선 된 버전이 있습니다.

function suptime() {
    local addr=${1:?Specify the remote IPv4 address}
    local port=${2:?Specify the remote port number}

    # convert the provided address to hex format
    local hex_addr=$(python -c "import socket, struct; print(hex(struct.unpack('<L', socket.inet_aton('$addr'))[0])[2:10].upper().zfill(8))")
    local hex_port=$(python -c "print(hex($port)[2:].upper().zfill(4))")

    # get the inode of the socket
    local inodes=$(awk '$4 == "01" && $3 == "'$hex_addr:$hex_port'" {print $10}' /proc/net/tcp)
    [ -z "$inodes" ] && { echo 'Cannot lookup the socket(s)' 2>&1; return 1; }

    # get file descriptors
    for inode in $inodes; do
        # get inode's file descriptor details
        local fdinfo=( $(find /proc/[0-9]*/fd -lname "socket:\[$inode\]" -printf "%p %T@") )
        [ -z "$fdinfo" ] && { echo 'Cannot find file descriptor' 2>&1; return 1; }

        # extract pid
        local fdpath=${fdinfo[0]}
        local pid=${fdpath#/proc/}
        pid=${pid%%/*}

        # extract timestamp
        local timestamp=${fdinfo[1]}

        # compute the time difference
        LANG=C printf 'PID: %s; Age: %s (%.2fs ago)\n' "$pid" "$(date -d @$timestamp)" $(bc <<<"$(date +%s.%N) - $timestamp")
    done
}

노트:

  • needs bc, netstat( net-toolsrhel> = 7 및 유사한 시스템에서 제공)
  • 루트로 실행해야합니다
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.