如何在Linux中查找进程ID打开的端口?

60
假设进程的PID已知。

9
这个问题应该在serverfault.com上问吗? - cd1
@cd1 我仍然不确定这应该提交给serverfault.com还是Unix&Linux。 - Valerio Bozz
7个回答

87
netstat --all --program | grep '3265'
  • --all 显示监听和非监听的套接字。
  • --program 显示套接字所属程序的PID和名称。

你也可以使用像Nmap这样的端口扫描器。


1
哦,我好像没有“--all”和“--program”选项。我正在使用OSX操作系统。Brew似乎也没有相关的配方。 - ming_codes
3
OSX预装了nettop,我认为它比netstat更适合这种情况。 - BaronVonKaneHoffen
5
使用-n选项可以大幅提升速度,但不会解析主机名。netstat -tupan是一个很好记的默认命令。 - Ciro Santilli OurBigBook.com
1
"sudo netstat -ap" 是相同命令的缩写版本。 - Soumen
ss -anp | grep '3265' 也可以工作。命令 ssiproute2 的一部分,它是 net-tool 的替代品。 - rustyhu

30

您可以使用以下命令:

lsof -i -P |grep pid

1
这个在我的CENTOS7上运行成功了,谢谢@Watever! - Gaucho

9

顺带一提,netstat -ao 命令会读取 /proc/PID/tcp 等文件,以查看进程开放的端口。这意味着它在读取系统(Linux 内核)提供的信息,而且并不是直接查看网络接口或其他手段。

如果您将此用作安全措施,那么失败了。您绝不能(绝对不能)信任 netstat 的输出,即使您百分之百确定您实际上正在运行真正的 netstat 程序(而不是木马版本)或任何其他读取 /proc 文件系统的程序。有些人似乎认为 netstat、ls、ps 或其他任何标准 Unix 工具都可以从源头获取信息,事实上,它们都依赖于 /proc 文件系统获取所有数据,而这很容易被 rootkit 或 hypervisor 篡改。


9
如果您正在处理一个被植入rootkit的系统或被攻击的hypervisor,那么您不能相信任何东西,包括声称可以直接查看网络接口的工具。 - Rag
我不认为这个反对意见有很高的意义。对物理网络接口/芯片的访问是由操作系统和操作系统的网络层进行调节的;物理网络接口主要处理数据包缓冲区,只有操作系统才知道哪些进程ID在使用它。因此,操作系统是获取这些信息的主要位置,netstat是主要工具。我相信在现实中,netstat是有用的,包括在某些安全情况下。如果这个答案提出一个更可靠的替代方案,它可能会更好。 - undefined

8
您可以使用-p命令行参数和netstat命令行工具:

-p(Linux):

进程:显示哪些进程正在使用哪些套接字(类似于Windows下的-b)。您必须是root用户才能执行此操作。

示例部分提供了以下示例:

To display all ports open by a process with id $PID:

netstat -ao | grep '\b'$PID'\b'

5

在一些嵌入式设备或旧版Linux中,问题是netstat没有可用的--process-p选项。

以下脚本显示带有其IP和端口的进程,您必须拥有root权限。

#!/bin/bash

for protocol in tcp udp ; 
do 
    #echo "protocol $protocol" ; 
    for ipportinode in `cat /proc/net/${protocol} | awk '/.*:.*:.*/{print $2"|"$3"|"$10 ;}'` ; 
    do 
        #echo "#ipportinode=$ipportinode"
        inode=`echo "$ipportinode" | cut -d"|" -f3` ;
        if [ "#$inode" = "#" ] ; then continue ; fi 
        lspid=`ls -l /proc/*/fd/* 2>/dev/null | grep "socket:\[$inode\]" 2>/dev/null` ; 
        pid=`echo "lspid=$lspid" | awk 'BEGIN{FS="/"} /socket/{print $3}'` ;
        if [ "#$pid" = "#" ] ; then continue ; fi
        exefile=`ls -l /proc/$pid/exe | awk 'BEGIN{FS=" -> "}/->/{print $2;}'`
        #echo "$protocol|$pid|$ipportinode" 
        echo "$protocol|$pid|$ipportinode|$exefile" | awk '
            BEGIN{FS="|"}
            function iphex2dec(ipport){ 
                ret=sprintf("%d.%d.%d.%d:    %d","0x"substr(ipport,1,2),"0x"substr(ipport,3,2),
                "0x"substr(ipport,5,2),"0x"substr(ipport,7,2),"0x"substr(ipport,10,4)) ;
                if( ret == "0.0.0.0:0" ) #compatibility others awk versions 
                {
                    ret=        strtonum("0x"substr(ipport,1,2)) ;
                    ret=ret "." strtonum("0x"substr(ipport,3,2)) ;
                    ret=ret "." strtonum("0x"substr(ipport,5,2)) ;
                    ret=ret "." strtonum("0x"substr(ipport,7,2)) ;
                    ret=ret ":" strtonum("0x"substr(ipport,10)) ;
                }
                return ret ;
            }
            { 
            print $1" pid:"$2" local="iphex2dec($3)" remote="iphex2dec($4)" inode:"$5" exe=" $6 ;  
            }
            ' ; 
        #ls -l /proc/$pid/exe ; 
    done ; 
done

输出结果如下:
tcp pid:1454 local=1.0.0.127:5939 remote=0.0.0.0:0 inode:13955 exe=/opt/teamviewer/tv_bin/teamviewerd
tcp pid:1468 local=1.1.0.127:53 remote=0.0.0.0:0 inode:12757 exe=/usr/sbin/dnsmasq
tcp pid:1292 local=0.0.0.0:22 remote=0.0.0.0:0 inode:12599 exe=/usr/sbin/sshd
tcp pid:4361 local=1.0.0.127:631 remote=0.0.0.0:0 inode:30576 exe=/usr/sbin/cupsd
tcp pid:1375 local=1.0.0.127:5432 remote=0.0.0.0:0 inode:12650 exe=/usr/lib/postgresql/9.3/bin/postgres

2

1
我已经添加了IPv6支持并进行了一些修复。另外,在我的系统上,IP地址的八位组是反向的。依赖项仅限于posix shell、awk和cut。
我的版本可以在Github上找到。
#!/bin/sh


# prints all open ports from /proc/net/* 
#
# for pretty output (if available) start with 
# ./linux-get-programm-to-port.sh | column -t -s $'\t' 


#set -x

ip4hex2dec () {
    local ip4_1octet="0x${1%???????????}"

    local ip4_2octet="${1%?????????}"
    ip4_2octet="0x${ip4_2octet#??}"

    local ip4_3octet="${1%???????}"
    ip4_3octet="0x${ip4_3octet#????}"

    local ip4_4octet="${1%?????}"
    ip4_4octet="0x${ip4_4octet#??????}"

    local ip4_port="0x${1##*:}"

    # if not used inverse
    #printf "%d.%d.%d.%d:%d" "$ip4_1octet" "$ip4_2octet" "$ip4_3octet" "$ip4_4octet" "$ip4_port"
    printf "%d.%d.%d.%d:%d" "$ip4_4octet" "$ip4_3octet" "$ip4_2octet" "$ip4_1octet" "$ip4_port"
}


# reoder bytes, byte4 is byte1 byte2 is byte3 ...
reorderByte(){
    if [ ${#1} -ne 8 ]; then echo "missuse of function reorderByte"; exit; fi

    local byte1="${1%??????}"

    local byte2="${1%????}"
    byte2="${byte2#??}"

    local byte3="${1%??}"
    byte3="${byte3#????}"

    local byte4="${1#??????}"

    echo "$byte4$byte3:$byte2$byte1"
}

# on normal intel platform the byte order of the ipv6 address in /proc/net/*6 has to be reordered.
ip6hex2dec(){
    local ip_str="${1%%:*}"
    local ip6_port="0x${1##*:}"
    local ipv6="$(reorderByte ${ip_str%????????????????????????})"
    local shiftmask="${ip_str%????????????????}"
    ipv6="$ipv6:$(reorderByte ${shiftmask#????????})"
    shiftmask="${ip_str%????????}"
    ipv6="$ipv6:$(reorderByte ${shiftmask#????????????????})"
    ipv6="$ipv6:$(reorderByte ${ip_str#????????????????????????})"
    ipv6=$(echo $ipv6 | awk '{ gsub(/(:0{1,3}|^0{1,3})/, ":"); sub(/(:0)+:/, "::");print}')
    printf "%s:%d" "$ipv6" "$ip6_port"
}

for protocol in tcp tcp6 udp udp6 raw raw6; 
do 
    #echo "protocol $protocol" ; 
    for ipportinode in `cat /proc/net/$protocol | awk '/.*:.*:.*/{print $2"|"$3"|"$10 ;}'` ; 
    do 
        #echo "#ipportinode=$ipportinode"
        inode=${ipportinode##*|}
        if [ "#$inode" = "#" ] ; then continue ; fi 

        lspid=`ls -l /proc/*/fd/* 2>/dev/null | grep "socket:\[$inode\]" 2>/dev/null` ; 
        pids=`echo "$lspid" | awk 'BEGIN{FS="/"} /socket/{pids[$3]} END{for (pid in pids) {print pid;}}'` ;  # removes duplicats for this pid
        #echo "#lspid:$lspid  #pids:$pids"

        for pid in $pids; do
            if [ "#$pid" = "#" ] ; then continue ; fi
            exefile=`ls -l /proc/$pid/exe | awk 'BEGIN{FS=" -> "}/->/{print $2;}'`;
            cmdline=`cat /proc/$pid/cmdline`

            local_adr_hex=${ipportinode%%|*}
            remote_adr_hex=${ipportinode#*|}
            remote_adr_hex=${remote_adr_hex%%|*}

            if [ "#${protocol#???}" = "#6" ]; then
                local_adr=$(ip6hex2dec $local_adr_hex)
                remote_adr=$(ip6hex2dec $remote_adr_hex)
            else
        local_adr=$(ip4hex2dec $local_adr_hex)
        remote_adr=$(ip4hex2dec $remote_adr_hex)
            fi 

            echo "$protocol pid:$pid \t$local_adr \t$remote_adr \tinode:$inode \t$exefile $cmdline" 
    done
    done  
done

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接