patternpythonMinor
Locating a PID based on an IP address and port
Viewed 0 times
addresslocatingandbasedportpid
Problem
I wrote a simple Python app that is given an IP address and port and the app then finds the PID listening on that IP:PORT.
I would like to hear constructive criticism regarding the bellow code.
I would like to hear constructive criticism regarding the bellow code.
import argparse
import sys
import socket
import subprocess
import os
def is_legal_ip(address):
ip = address.split(":")
pieces = ip[0].split('.')
if len(pieces) != 4:
return False
try:
return all(0 2 or len(sys.argv) == 1:
print("Please provide a single argument.")
exit(1)
parser = argparse.ArgumentParser("Returns a PID listenning on IP:PORT")
parser.add_argument('ip_port', metavar='IP:PORT', type=str, nargs=1, help='local address')
args = parser.parse_args()
if (is_legal_ip(args.ip_port[0]) == False):
print("Invalid IP address.")
exit(1)
return(args.ip_port[0])
def address_to_pid(ip_port):
devnull = open(os.devnull, 'w')
output = subprocess.check_output("netstat -nptl".split(), stderr = devnull).splitlines()
devnull.close()
for line in output[2::]:
raw_line = line.split()
if raw_line[3] == ip_port:
if raw_line[6] == "-":
return "No PID listening on address"
else:
return raw_line[6].split(r"/")[0]
def main():
ip_port = parse_arguments()
print address_to_pid(ip_port)
if __name__ == "__main__": main()Solution
First off, a couple of quick tips:
Leave the job of argument parsing to argparse
- Follow the PEP8 style guide
- Instead of
x == False, usenot x, for example inif (is_legal_ip(args.ip_port[0]) == False)
- Omit unnecessary imports (
import socketin this example)
- Use spaces around operators, for example
all(0
- Break lines after colons, for example in if __name__ == "__main__": main()
Leave the job of argument parsing to argparse
No need to work with sys.args yourself.
For example you can simply remove these lines:
if len(sys.argv) > 2 or len(sys.argv) == 1:
print("Please provide a single argument.")
exit(1)
The way you specified the ip-port arguments with nargs=1,
argparse will take care of validating the number of command line arguments.
Simplify the argument parsing
You can omit nargs=1.
But in that case,
the value of args.ip_port will not be a list,
but a simple string.
You can also omit the type=str, as that's the default.
Your usage would become simpler:
parser.add_argument('ip_port', metavar='IP:PORT', help='local address')
args = parser.parse_args()
if not is_legal_ip(args.ip_port):
parser.error("Invalid IP address.")
return args.ip_port
Use two arguments instead of one
It's awkward that use ip:port,
the splitting at multiple places is just noise.
It will be simpler and cleaner to use two arguments instead of one:
parser.add_argument('ip', help='local address')
parser.add_argument('port', type=int, help='local port')
args = parser.parse_args()
if not is_legal_ip(args.ip):
parser.error("Invalid IP address.")
return args.ip, args.port
Notice that this way argparse can take care of validating the port number.
Then in your main function, you can get the ip address and port pair like this:
ip, port = parse_arguments()
Benefit from the error reporting features of argparse
Instead of this:
if not is_legal_ip(args.ip_port):
print("Invalid IP address.")
exit(1)
I suggest to use this way:
if not is_legal_ip(args.ip_port):
parser.error("Invalid IP address.")
argparse will print a usage help along with the error message,
and also exit.
A subtlety here is that argparse will exit with code 2 in this case,
which is common in case of invalid parameters of UNIX commands.
Working with file handles
When working with files, use with:
with open(os.devnull, 'w') as devnull:
output = subprocess.check_output("netstat -nl".split(), stderr=devnull).splitlines()
This makes devnull.close()` unnecessary, Python will call it when exiting the block.Code Snippets
if len(sys.argv) > 2 or len(sys.argv) == 1:
print("Please provide a single argument.")
exit(1)parser.add_argument('ip_port', metavar='IP:PORT', help='local address')
args = parser.parse_args()
if not is_legal_ip(args.ip_port):
parser.error("Invalid IP address.")
return args.ip_portparser.add_argument('ip', help='local address')
parser.add_argument('port', type=int, help='local port')
args = parser.parse_args()
if not is_legal_ip(args.ip):
parser.error("Invalid IP address.")
return args.ip, args.portip, port = parse_arguments()if not is_legal_ip(args.ip_port):
print("Invalid IP address.")
exit(1)Context
StackExchange Code Review Q#98377, answer score: 9
Revisions (0)
No revisions yet.