I know I am several years late, but non of the existing answers are good enough.
I was Google searching for a good, elegant solution for exactly the same problem and non of the answers already posted seemed good enough, instead I have found solutions of my own and I want to post them here to help future readers who get redirected here by Google.
Most operating systems have an executable named netstat
, that can be used to capture listening ports, in this example I am using Windows 10 and Python 3.9.6 x64, but this is written Python so you can easily adapt it for your own use case.
Using plain netstat
will be very slow, because of all the name-resolving, using netstat -n
will be exponentially faster because it doesn't waste time resolving the names.
In Python 3.9.6, use subproces.run()
to run os calls, and use capture_output=True
to capture stdout, then use .stdout
property of resultant process to get output, the result is in binary form, use .decode()
to get string.
Then the output should look like this:
Active Connections
Proto Local Address Foreign Address State
TCP 10.70.0.6:1134 40.83.240.146:443 ESTABLISHED
TCP 10.70.0.6:1283 117.18.232.200:443 CLOSE_WAIT
TCP 10.70.0.6:1609 198.252.206.25:443 ESTABLISHED
TCP 10.70.0.6:1621 198.252.206.25:443 ESTABLISHED
TCP 10.70.0.6:1691 74.125.24.102:443 ESTABLISHED
TCP 10.70.0.6:1727 142.251.10.94:443 ESTABLISHED
TCP 10.70.0.6:1728 142.251.10.100:443 TIME_WAIT
TCP 10.70.0.6:1731 172.217.194.119:443 TIME_WAIT
TCP 10.70.0.6:1735 74.125.24.113:443 ESTABLISHED
TCP 10.70.0.6:1787 104.244.42.130:443 ESTABLISHED
TCP 10.70.0.6:1796 151.101.1.69:443 ESTABLISHED
TCP 10.70.0.6:1797 151.101.196.193:443 ESTABLISHED
TCP 10.70.0.6:1799 74.125.130.132:443 ESTABLISHED
TCP 10.70.0.6:1800 198.252.206.25:443 ESTABLISHED
TCP 10.70.0.6:1805 3.209.45.230:443 TIME_WAIT
TCP 10.70.0.6:1806 3.219.6.82:443 TIME_WAIT
TCP 10.70.0.6:1807 3.211.239.214:443 TIME_WAIT
TCP 10.70.0.6:1816 140.82.113.26:443 ESTABLISHED
TCP 127.0.0.1:1053 127.0.0.1:1055 ESTABLISHED
TCP 127.0.0.1:1055 127.0.0.1:1053 ESTABLISHED
TCP 127.0.0.1:1057 127.0.0.1:1058 ESTABLISHED
TCP 127.0.0.1:1058 127.0.0.1:1057 ESTABLISHED
TCP 127.0.0.1:1061 127.0.0.1:1062 ESTABLISHED
TCP 127.0.0.1:1062 127.0.0.1:1061 ESTABLISHED
TCP 127.0.0.1:1763 127.0.0.1:1764 ESTABLISHED
TCP 127.0.0.1:1764 127.0.0.1:1763 ESTABLISHED
TCP 127.0.0.1:1766 127.0.0.1:1767 ESTABLISHED
TCP 127.0.0.1:1767 127.0.0.1:1766 ESTABLISHED
TCP 127.0.0.1:1810 127.0.0.1:2015 ESTABLISHED
TCP 127.0.0.1:1811 127.0.0.1:2015 ESTABLISHED
TCP 127.0.0.1:1820 127.0.0.1:1821 ESTABLISHED
TCP 127.0.0.1:1821 127.0.0.1:1820 ESTABLISHED
TCP 127.0.0.1:1829 127.0.0.1:9614 SYN_SENT
TCP 127.0.0.1:2015 127.0.0.1:1810 ESTABLISHED
TCP 127.0.0.1:2015 127.0.0.1:1811 ESTABLISHED
TCP 127.0.0.1:14845 127.0.0.1:14846 ESTABLISHED
TCP 127.0.0.1:14846 127.0.0.1:14845 ESTABLISHED
TCP 127.0.0.1:15004 127.0.0.1:15005 ESTABLISHED
TCP 127.0.0.1:15005 127.0.0.1:15004 ESTABLISHED
TCP 127.0.0.1:15013 127.0.0.1:15014 ESTABLISHED
TCP 127.0.0.1:15014 127.0.0.1:15013 ESTABLISHED
TCP 127.0.0.1:16976 127.0.0.1:16977 ESTABLISHED
TCP 127.0.0.1:16977 127.0.0.1:16976 ESTABLISHED
TCP 127.0.0.1:19278 127.0.0.1:19279 ESTABLISHED
TCP 127.0.0.1:19279 127.0.0.1:19278 ESTABLISHED
TCP 127.0.0.1:19280 127.0.0.1:19281 ESTABLISHED
TCP 127.0.0.1:19281 127.0.0.1:19280 ESTABLISHED
TCP 127.0.0.1:20695 127.0.0.1:21385 ESTABLISHED
TCP 127.0.0.1:21385 127.0.0.1:20695 ESTABLISHED
TCP 127.0.0.1:23460 127.0.0.1:23461 ESTABLISHED
TCP 127.0.0.1:23461 127.0.0.1:23460 ESTABLISHED
TCP 127.0.0.1:23462 127.0.0.1:23463 ESTABLISHED
TCP 127.0.0.1:23463 127.0.0.1:23462 ESTABLISHED
TCP 127.0.0.1:28343 127.0.0.1:28344 ESTABLISHED
TCP 127.0.0.1:28344 127.0.0.1:28343 ESTABLISHED
TCP 127.0.0.1:30307 127.0.0.1:30308 ESTABLISHED
TCP 127.0.0.1:30308 127.0.0.1:30307 ESTABLISHED
TCP 127.0.0.1:30311 127.0.0.1:30312 ESTABLISHED
TCP 127.0.0.1:30312 127.0.0.1:30311 ESTABLISHED
TCP 127.0.0.1:30313 127.0.0.1:30314 ESTABLISHED
TCP 127.0.0.1:30314 127.0.0.1:30313 ESTABLISHED
TCP 127.0.0.1:30316 127.0.0.1:30317 ESTABLISHED
TCP 127.0.0.1:30317 127.0.0.1:30316 ESTABLISHED
TCP 127.0.0.1:30319 127.0.0.1:30320 ESTABLISHED
TCP 127.0.0.1:30320 127.0.0.1:30319 ESTABLISHED
TCP 127.0.0.1:30584 127.0.0.1:30585 ESTABLISHED
TCP 127.0.0.1:30585 127.0.0.1:30584 ESTABLISHED
TCP 127.0.0.1:30623 127.0.0.1:30624 ESTABLISHED
TCP 127.0.0.1:30624 127.0.0.1:30623 ESTABLISHED
TCP 127.0.0.1:49669 127.0.0.1:49670 ESTABLISHED
TCP 127.0.0.1:49670 127.0.0.1:49669 ESTABLISHED
TCP 127.0.0.1:49690 127.0.0.1:49692 ESTABLISHED
TCP 127.0.0.1:49692 127.0.0.1:49690 ESTABLISHED
TCP [::1]:3306 [::1]:23468 ESTABLISHED
TCP [::1]:3306 [::1]:23469 ESTABLISHED
TCP [::1]:23468 [::1]:3306 ESTABLISHED
TCP [::1]:23469 [::1]:3306 ESTABLISHED
Use splitlines()
to get separate lines, then use list slicing to get the contents of the actual table, here we use index 4, then using regex splitting to split on whitespace characters, then use index to get the local address value, then finally use string split on colons and indexing to get the ports.
The code:
import psutil
import re
import subprocess
def get_active_ports():
process = subprocess.run(['netstat', '-n'], capture_output=True)
report = process.stdout.decode().splitlines()
ports = set()
for i in report[4:]:
ports.add(re.split(':(?!.*:)', re.split('\s+', i)[2])[1])
return ports
Or in one-liner:
set([re.split(':(?!.*:)', re.split('\s+', i)[2])[1] for i in subprocess.run(['netstat', '-n'], capture_output=True).stdout.decode().splitlines()[4:]])
Performance:
In [119]: %timeit set([re.split(':(?!.*:)', re.split('\s+', i)[2])[1] for i in subprocess.run(['netstat', '-n'], capture_output=True).stdout.decode().splitlines()[4:]])
11.4 ms ± 315 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Or, alternatively, psutil
has a .net_connections()
method, you can just get the ports from it.
Just use set comprehension to grab the output:
set(i.laddr.port for i in psutil.net_connections())
This approach is tremendously faster than the previous one:
In [103]: %timeit set(i.laddr.port for i in psutil.net_connections())
893 µs ± 13.1 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)