Finding a process ID given a socket and inode in P

2020-02-29 06:50发布

问题:

/proc/net/tcp gives me a local address, port, and inode number for a socket (0.0.0.0:5432 and 9289, for example).

I'd like to find the PID for a specific process, given the above information.

It's possible to open every numbered folder in /proc, and then check symlinks for matching socket/inode numbers with a shell command like "$ sudo ls -l /proc/*/fd/ 2>/dev/null | grep socket". However, this seems more computationally expensive than necessary, since <5% of the processes on any given system have open TCP sockets.

What's the most efficient way to find the PID which has opened a given socket? I'd prefer to use standard libraries, and I'm currently developing with Python 3.2.3.

Edit: Removed the code samples from the question, since they are now included in the answer below.

回答1:

The following code accomplishes the original goal:

def find_pid(inode):

    # get a list of all files and directories in /proc
    procFiles = os.listdir("/proc/")

    # remove the pid of the current python process
    procFiles.remove(str(os.getpid()))

    # set up a list object to store valid pids
    pids = []

    for f in procFiles:
        try:
            # convert the filename to an integer and back, saving the result to a list
            integer = int(f)
            pids.append(str(integer))
        except ValueError:
            # if the filename doesn't convert to an integer, it's not a pid, and we don't care about it
            pass

    for pid in pids:
        # check the fd directory for socket information
        fds = os.listdir("/proc/%s/fd/" % pid)
        for fd in fds:
            # save the pid for sockets matching our inode
            if ('socket:[%d]' % inode) == os.readlink("/proc/%s/fd/%s" % (pid, fd)):
                return pid


回答2:

I do not know how to do this in python, but you could use lsof(1):

lsof -i | awk -v sock=158384387 '$6 == sock{print $2}'

158384387 is the inode for the socket. And then call it from python using subprocess.Popen.

You will have to use sudo(8) if you want to see sockets opened by other users.