kport 1.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- kport-1.0.0.dist-info/METADATA +361 -0
- kport-1.0.0.dist-info/RECORD +7 -0
- kport-1.0.0.dist-info/WHEEL +5 -0
- kport-1.0.0.dist-info/entry_points.txt +2 -0
- kport-1.0.0.dist-info/licenses/LICENSE +21 -0
- kport-1.0.0.dist-info/top_level.txt +1 -0
- kport.py +440 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: kport
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: A cross-platform command-line tool to inspect and kill processes using specific ports
|
|
5
|
+
Home-page: https://github.com/farman20ali/port-killer
|
|
6
|
+
Author: Farman Ali (Alien)
|
|
7
|
+
Author-email: farman20ali@example.com
|
|
8
|
+
Project-URL: Bug Reports, https://github.com/farman20ali/port-killer/issues
|
|
9
|
+
Project-URL: Source, https://github.com/farman20ali/port-killer
|
|
10
|
+
Keywords: port,kill,process,network,cross-platform,cli
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Intended Audience :: System Administrators
|
|
14
|
+
Classifier: Topic :: System :: Networking
|
|
15
|
+
Classifier: Topic :: System :: Systems Administration
|
|
16
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.6
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
23
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
24
|
+
Classifier: Operating System :: OS Independent
|
|
25
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
26
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
27
|
+
Classifier: Operating System :: MacOS
|
|
28
|
+
Requires-Python: >=3.6
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
License-File: LICENSE
|
|
31
|
+
Dynamic: author
|
|
32
|
+
Dynamic: author-email
|
|
33
|
+
Dynamic: classifier
|
|
34
|
+
Dynamic: description
|
|
35
|
+
Dynamic: description-content-type
|
|
36
|
+
Dynamic: home-page
|
|
37
|
+
Dynamic: keywords
|
|
38
|
+
Dynamic: license-file
|
|
39
|
+
Dynamic: project-url
|
|
40
|
+
Dynamic: requires-python
|
|
41
|
+
Dynamic: summary
|
|
42
|
+
|
|
43
|
+
# šŖ kport - Cross-Platform Port Inspector and Killer
|
|
44
|
+
|
|
45
|
+
A simple, powerful command-line tool to inspect and kill processes using specific ports on Windows, Linux, and macOS.
|
|
46
|
+
|
|
47
|
+
## ⨠Features
|
|
48
|
+
|
|
49
|
+
- š **Inspect ports** - Find which process is using a specific port
|
|
50
|
+
- š **Inspect by process name** - Find all processes matching a name and their ports
|
|
51
|
+
- šŖ **Kill processes** - Terminate processes using specific ports
|
|
52
|
+
- š **List all ports** - View all listening ports and their processes
|
|
53
|
+
- šÆ **Kill by process name** - Kill all processes matching a name (e.g., "node", "python")
|
|
54
|
+
- š„ **Kill multiple ports** - Kill processes on multiple ports at once
|
|
55
|
+
- šØ **Colorized output** - Easy-to-read colored terminal output
|
|
56
|
+
- ā
**Confirmation prompts** - Safety confirmation before killing processes
|
|
57
|
+
- š **Cross-platform** - Works on Windows, Linux, and macOS
|
|
58
|
+
- š **Easy to use** - Simple command-line interface
|
|
59
|
+
|
|
60
|
+
## š¦ Installation
|
|
61
|
+
|
|
62
|
+
### Quick Install (Once Published to PyPI)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install kport
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Install from GitHub
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
pip install git+https://github.com/farman20ali/port-killer.git
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### Install from Source
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
# Clone the repository
|
|
78
|
+
git clone https://github.com/farman20ali/port-killer.git
|
|
79
|
+
cd port-killer
|
|
80
|
+
|
|
81
|
+
# Install
|
|
82
|
+
pip install .
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### Install for Development
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# Install in editable mode
|
|
89
|
+
pip install -e .
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
After installation, `kport` will be available globally in your terminal.
|
|
93
|
+
|
|
94
|
+
### Run Without Installing
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
# Run directly with Python
|
|
98
|
+
python kport.py -h
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
> š For detailed installation instructions, see [INSTALL.md](INSTALL.md)
|
|
102
|
+
>
|
|
103
|
+
> š For publishing instructions, see [PUBLISH.md](PUBLISH.md)
|
|
104
|
+
|
|
105
|
+
## š Usage
|
|
106
|
+
|
|
107
|
+
### Inspect a port
|
|
108
|
+
|
|
109
|
+
Find out which process is using a specific port:
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
kport -i 8080
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Example output:
|
|
116
|
+
```
|
|
117
|
+
š Inspecting port 8080...
|
|
118
|
+
|
|
119
|
+
ā Port 8080 is being used by PID 12345
|
|
120
|
+
|
|
121
|
+
Process Information:
|
|
122
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
123
|
+
PID: 12345
|
|
124
|
+
Image Name: node.exe
|
|
125
|
+
Session Name: Console
|
|
126
|
+
Mem Usage: 45,678 K
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
### Inspect by process name
|
|
130
|
+
|
|
131
|
+
Find all processes matching a name and see what ports they're using:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
kport -ip node
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Example output:
|
|
138
|
+
```
|
|
139
|
+
š Inspecting processes matching 'node'...
|
|
140
|
+
|
|
141
|
+
Found 3 connection(s) for processes matching 'node':
|
|
142
|
+
|
|
143
|
+
PID Process Port State
|
|
144
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
145
|
+
12345 node.exe 3000 LISTENING
|
|
146
|
+
3001 LISTENING
|
|
147
|
+
12346 node.exe 8080 LISTENING
|
|
148
|
+
|
|
149
|
+
ā Total processes found: 2
|
|
150
|
+
ā Total connections: 3
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Kill a process on a port
|
|
154
|
+
|
|
155
|
+
Terminate the process using a specific port:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
kport -k 8080
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Example output:
|
|
162
|
+
```
|
|
163
|
+
šŖ Attempting to kill process on port 8080...
|
|
164
|
+
|
|
165
|
+
Found PID 12345 using port 8080
|
|
166
|
+
|
|
167
|
+
Process to be terminated:
|
|
168
|
+
PID: 12345
|
|
169
|
+
Image Name: node.exe
|
|
170
|
+
|
|
171
|
+
Are you sure you want to kill this process? (y/N): y
|
|
172
|
+
|
|
173
|
+
ā Successfully killed process 12345
|
|
174
|
+
Port 8080 is now free.
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### List all listening ports
|
|
178
|
+
|
|
179
|
+
View all active listening ports and their associated processes:
|
|
180
|
+
|
|
181
|
+
```bash
|
|
182
|
+
kport -l
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Example output:
|
|
186
|
+
```
|
|
187
|
+
š Listing all active ports...
|
|
188
|
+
|
|
189
|
+
Protocol Local Address State PID
|
|
190
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
191
|
+
TCP 0.0.0.0:80 LISTENING 1234
|
|
192
|
+
TCP 0.0.0.0:443 LISTENING 1234
|
|
193
|
+
TCP 0.0.0.0:3000 LISTENING 5678
|
|
194
|
+
TCP 0.0.0.0:8080 LISTENING 9012
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
### Kill by process name
|
|
198
|
+
|
|
199
|
+
Kill all processes matching a specific name:
|
|
200
|
+
|
|
201
|
+
```bash
|
|
202
|
+
kport -kp node
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Example output:
|
|
206
|
+
```
|
|
207
|
+
šŖ Killing all processes matching 'node'...
|
|
208
|
+
|
|
209
|
+
Found 3 process(es) matching 'node':
|
|
210
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
211
|
+
PID 12345: node.exe
|
|
212
|
+
PID 12346: node.exe
|
|
213
|
+
PID 12347: node.exe
|
|
214
|
+
|
|
215
|
+
Are you sure you want to kill 3 process(es)? (y/N): y
|
|
216
|
+
|
|
217
|
+
ā Killed PID 12345
|
|
218
|
+
ā Killed PID 12346
|
|
219
|
+
ā Killed PID 12347
|
|
220
|
+
|
|
221
|
+
ā Successfully killed 3/3 process(es)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Kill multiple ports at once
|
|
225
|
+
|
|
226
|
+
Kill processes on multiple ports simultaneously:
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
kport -ka 3000 3001 3002
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Example output:
|
|
233
|
+
```
|
|
234
|
+
šŖ Killing processes on 3 port(s)...
|
|
235
|
+
|
|
236
|
+
Found processes on 3 port(s):
|
|
237
|
+
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
238
|
+
Port 3000: PID 12345 (node.exe)
|
|
239
|
+
Port 3001: PID 12346 (node.exe)
|
|
240
|
+
Port 3002: PID 12347 (python.exe)
|
|
241
|
+
|
|
242
|
+
Are you sure you want to kill 3 process(es)? (y/N): y
|
|
243
|
+
|
|
244
|
+
ā Killed process on port 3000 (PID 12345)
|
|
245
|
+
ā Killed process on port 3001 (PID 12346)
|
|
246
|
+
ā Killed process on port 3002 (PID 12347)
|
|
247
|
+
|
|
248
|
+
ā Successfully killed 3/3 process(es)
|
|
249
|
+
Ports freed: 3000, 3001, 3002
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Show help
|
|
253
|
+
|
|
254
|
+
```bash
|
|
255
|
+
kport -h
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Show version
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
kport -v
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## š Command-Line Options
|
|
265
|
+
|
|
266
|
+
| Option | Long Form | Description |
|
|
267
|
+
|--------|-----------|-------------|
|
|
268
|
+
| `-i PORT` | `--inspect PORT` | Inspect which process is using the specified port |
|
|
269
|
+
| `-ip NAME` | `--inspect-process NAME` | Inspect all processes matching the given name and their ports |
|
|
270
|
+
| `-k PORT` | `--kill PORT` | Kill the process using the specified port |
|
|
271
|
+
| `-kp NAME` | `--kill-process NAME` | Kill all processes matching the given name |
|
|
272
|
+
| `-ka PORT [PORT ...]` | `--kill-all PORT [PORT ...]` | Kill processes on multiple ports at once |
|
|
273
|
+
| `-l` | `--list` | List all listening ports and their processes |
|
|
274
|
+
| `-v` | `--version` | Show version information |
|
|
275
|
+
| `-h` | `--help` | Show help message |
|
|
276
|
+
|
|
277
|
+
## š ļø Requirements
|
|
278
|
+
|
|
279
|
+
- Python 3.6 or higher
|
|
280
|
+
- No external dependencies (uses only Python standard library)
|
|
281
|
+
|
|
282
|
+
### Platform-specific tools
|
|
283
|
+
|
|
284
|
+
The tool uses platform-native commands:
|
|
285
|
+
|
|
286
|
+
- **Windows**: `netstat`, `tasklist`, `taskkill`
|
|
287
|
+
- **Linux/macOS**: `lsof`, `ps`, `kill`
|
|
288
|
+
|
|
289
|
+
These tools are typically pre-installed on all platforms.
|
|
290
|
+
|
|
291
|
+
## š§ Development
|
|
292
|
+
|
|
293
|
+
### Clone and setup
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
git clone https://github.com/farman20ali/port-killer.git
|
|
297
|
+
cd port-killer
|
|
298
|
+
|
|
299
|
+
# Install in development mode
|
|
300
|
+
pip install -e .
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Run tests
|
|
304
|
+
|
|
305
|
+
```bash
|
|
306
|
+
# Test inspecting a port
|
|
307
|
+
kport -i 80
|
|
308
|
+
|
|
309
|
+
# Test listing ports
|
|
310
|
+
kport -l
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## š¤ Contributing
|
|
314
|
+
|
|
315
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
316
|
+
|
|
317
|
+
1. Fork the repository
|
|
318
|
+
2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
|
|
319
|
+
3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
|
|
320
|
+
4. Push to the branch (`git push origin feature/AmazingFeature`)
|
|
321
|
+
5. Open a Pull Request
|
|
322
|
+
|
|
323
|
+
## š License
|
|
324
|
+
|
|
325
|
+
This project is licensed under the MIT License - see the LICENSE file for details.
|
|
326
|
+
|
|
327
|
+
## ā ļø Important Notes
|
|
328
|
+
|
|
329
|
+
- **Administrator/sudo privileges**: Killing processes may require elevated privileges on some systems
|
|
330
|
+
- **Port validation**: Port numbers must be between 1 and 65535
|
|
331
|
+
- **Safety**: The tool asks for confirmation before killing any process
|
|
332
|
+
- **Multiple processes**: If multiple processes use the same port, the first one found will be shown/killed
|
|
333
|
+
|
|
334
|
+
## š Troubleshooting
|
|
335
|
+
|
|
336
|
+
### "Permission denied" errors
|
|
337
|
+
|
|
338
|
+
On Linux/macOS, you may need to run with sudo:
|
|
339
|
+
```bash
|
|
340
|
+
sudo kport -k 80
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
On Windows, run your terminal as Administrator.
|
|
344
|
+
|
|
345
|
+
### Port not found
|
|
346
|
+
|
|
347
|
+
Make sure the port number is correct and that a process is actually using it. Use `kport -l` to see all active ports.
|
|
348
|
+
|
|
349
|
+
### Color output not working on Windows
|
|
350
|
+
|
|
351
|
+
Colors should work on Windows 10 and later. If you're on an older version, colors may not display correctly.
|
|
352
|
+
|
|
353
|
+
## š§ Contact
|
|
354
|
+
|
|
355
|
+
Your Name - your.email@example.com
|
|
356
|
+
|
|
357
|
+
Project Link: [https://github.com/yourusername/port-killer](https://github.com/yourusername/port-killer)
|
|
358
|
+
|
|
359
|
+
---
|
|
360
|
+
|
|
361
|
+
Made with ā¤ļø for developers who are tired of hunting down processes
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
kport.py,sha256=6nx8AasiXMfykoymzkqmAGTQ3OIMkEOoFcKYvApSGgQ,18043
|
|
2
|
+
kport-1.0.0.dist-info/licenses/LICENSE,sha256=QQ8MyuCI55RKsPJcc50I2sT59jvpRtD9kvA031BtYs8,1083
|
|
3
|
+
kport-1.0.0.dist-info/METADATA,sha256=zampNq2_T6Em0La-nnV2DwAtNLwoZsec6d7meG-GPt0,10183
|
|
4
|
+
kport-1.0.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
5
|
+
kport-1.0.0.dist-info/entry_points.txt,sha256=ppZIgJ1vrmYs2EO9NcVSFCaZj7oj7t6RnJo8ArPQiRo,37
|
|
6
|
+
kport-1.0.0.dist-info/top_level.txt,sha256=yzlMBPZ7a-pcCN4DR5MRPO-VjY3fWnILtFUQpEuA2xY,6
|
|
7
|
+
kport-1.0.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 kport
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
kport
|
kport.py
ADDED
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
kport - Cross-platform port inspector and killer
|
|
4
|
+
A simple command-line tool to inspect and kill processes using specific ports
|
|
5
|
+
"""
|
|
6
|
+
import argparse
|
|
7
|
+
import os
|
|
8
|
+
import platform
|
|
9
|
+
import subprocess
|
|
10
|
+
import sys
|
|
11
|
+
import re
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
# ANSI color codes
|
|
15
|
+
class Colors:
|
|
16
|
+
RED = '\033[91m'
|
|
17
|
+
GREEN = '\033[92m'
|
|
18
|
+
YELLOW = '\033[93m'
|
|
19
|
+
BLUE = '\033[94m'
|
|
20
|
+
MAGENTA = '\033[95m'
|
|
21
|
+
CYAN = '\033[96m'
|
|
22
|
+
WHITE = '\033[97m'
|
|
23
|
+
BOLD = '\033[1m'
|
|
24
|
+
RESET = '\033[0m'
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def colorize(text, color):
|
|
28
|
+
"""Add color to text if terminal supports it"""
|
|
29
|
+
if platform.system() == "Windows":
|
|
30
|
+
# Enable ANSI colors on Windows 10+
|
|
31
|
+
os.system("")
|
|
32
|
+
return f"{color}{text}{Colors.RESET}"
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def run(cmd):
|
|
36
|
+
"""Execute shell command and return output"""
|
|
37
|
+
try:
|
|
38
|
+
return subprocess.check_output(cmd, shell=True, text=True, stderr=subprocess.DEVNULL)
|
|
39
|
+
except subprocess.CalledProcessError:
|
|
40
|
+
return ""
|
|
41
|
+
except Exception as e:
|
|
42
|
+
print(colorize(f"Error executing command: {e}", Colors.RED))
|
|
43
|
+
return ""
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def validate_port(port):
|
|
47
|
+
"""Validate if port number is in valid range"""
|
|
48
|
+
if not (1 <= port <= 65535):
|
|
49
|
+
print(colorize(f"Error: Port {port} is not valid. Port must be between 1 and 65535.", Colors.RED))
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def find_pid(port):
|
|
54
|
+
"""Find process ID using given port"""
|
|
55
|
+
system = platform.system()
|
|
56
|
+
|
|
57
|
+
if system == "Windows":
|
|
58
|
+
out = run(f"netstat -ano | findstr :{port}")
|
|
59
|
+
if not out:
|
|
60
|
+
return None, None
|
|
61
|
+
|
|
62
|
+
# Parse the first line (could be multiple connections)
|
|
63
|
+
lines = out.strip().split('\n')
|
|
64
|
+
for line in lines:
|
|
65
|
+
parts = line.split()
|
|
66
|
+
if len(parts) >= 5:
|
|
67
|
+
pid = parts[-1]
|
|
68
|
+
proc_info = run(f'tasklist /FI "PID eq {pid}" /FO LIST')
|
|
69
|
+
return pid, proc_info
|
|
70
|
+
|
|
71
|
+
return None, None
|
|
72
|
+
|
|
73
|
+
else: # Linux, Ubuntu, macOS
|
|
74
|
+
out = run(f"lsof -t -i:{port}")
|
|
75
|
+
if not out:
|
|
76
|
+
return None, None
|
|
77
|
+
|
|
78
|
+
pid = out.strip().split('\n')[0] # Get first PID if multiple
|
|
79
|
+
proc_info = run(f"ps -p {pid} -o pid,user,command")
|
|
80
|
+
return pid, proc_info
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def list_all_ports():
|
|
84
|
+
"""List all listening ports and their processes"""
|
|
85
|
+
system = platform.system()
|
|
86
|
+
|
|
87
|
+
print(colorize("\nš Listing all active ports...\n", Colors.CYAN + Colors.BOLD))
|
|
88
|
+
|
|
89
|
+
if system == "Windows":
|
|
90
|
+
out = run("netstat -ano | findstr LISTENING")
|
|
91
|
+
if not out:
|
|
92
|
+
print(colorize("No listening ports found.", Colors.YELLOW))
|
|
93
|
+
return
|
|
94
|
+
|
|
95
|
+
print(colorize(f"{'Protocol':<10} {'Local Address':<25} {'State':<15} {'PID':<10}", Colors.BOLD))
|
|
96
|
+
print("ā" * 70)
|
|
97
|
+
|
|
98
|
+
for line in out.strip().split('\n'):
|
|
99
|
+
parts = line.split()
|
|
100
|
+
if len(parts) >= 5:
|
|
101
|
+
protocol = parts[0]
|
|
102
|
+
local_addr = parts[1]
|
|
103
|
+
state = parts[3]
|
|
104
|
+
pid = parts[4]
|
|
105
|
+
print(f"{protocol:<10} {local_addr:<25} {state:<15} {pid:<10}")
|
|
106
|
+
|
|
107
|
+
else: # Linux, Ubuntu, macOS
|
|
108
|
+
out = run("lsof -i -P -n | grep LISTEN")
|
|
109
|
+
if not out:
|
|
110
|
+
print(colorize("No listening ports found.", Colors.YELLOW))
|
|
111
|
+
return
|
|
112
|
+
|
|
113
|
+
print(colorize(f"{'Command':<20} {'PID':<10} {'User':<15} {'Address':<30}", Colors.BOLD))
|
|
114
|
+
print("ā" * 80)
|
|
115
|
+
|
|
116
|
+
for line in out.strip().split('\n'):
|
|
117
|
+
parts = line.split()
|
|
118
|
+
if len(parts) >= 9:
|
|
119
|
+
command = parts[0]
|
|
120
|
+
pid = parts[1]
|
|
121
|
+
user = parts[2]
|
|
122
|
+
address = parts[8]
|
|
123
|
+
print(f"{command:<20} {pid:<10} {user:<15} {address:<30}")
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def find_pids_by_process_name(process_name):
|
|
127
|
+
"""Find all PIDs matching a process name"""
|
|
128
|
+
system = platform.system()
|
|
129
|
+
pids = []
|
|
130
|
+
|
|
131
|
+
if system == "Windows":
|
|
132
|
+
out = run(f'tasklist /FI "IMAGENAME eq {process_name}*" /FO CSV /NH')
|
|
133
|
+
if out:
|
|
134
|
+
for line in out.strip().split('\n'):
|
|
135
|
+
parts = line.replace('"', '').split(',')
|
|
136
|
+
if len(parts) >= 2:
|
|
137
|
+
try:
|
|
138
|
+
pid = parts[1]
|
|
139
|
+
pids.append(pid)
|
|
140
|
+
except (ValueError, IndexError):
|
|
141
|
+
continue
|
|
142
|
+
else: # Linux, Ubuntu, macOS
|
|
143
|
+
out = run(f"pgrep -f {process_name}")
|
|
144
|
+
if out:
|
|
145
|
+
pids = [pid.strip() for pid in out.strip().split('\n') if pid.strip()]
|
|
146
|
+
|
|
147
|
+
return pids
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def get_process_name(pid):
|
|
151
|
+
"""Get process name from PID"""
|
|
152
|
+
system = platform.system()
|
|
153
|
+
|
|
154
|
+
if system == "Windows":
|
|
155
|
+
out = run(f'tasklist /FI "PID eq {pid}" /FO CSV /NH')
|
|
156
|
+
if out:
|
|
157
|
+
parts = out.strip().split(',')[0].replace('"', '')
|
|
158
|
+
return parts
|
|
159
|
+
else:
|
|
160
|
+
out = run(f"ps -p {pid} -o comm=")
|
|
161
|
+
if out:
|
|
162
|
+
return out.strip()
|
|
163
|
+
|
|
164
|
+
return "Unknown"
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def find_ports_by_process_name(process_name):
|
|
168
|
+
"""Find all ports used by processes matching a name"""
|
|
169
|
+
system = platform.system()
|
|
170
|
+
process_port_map = [] # List of tuples: (pid, process_name, port)
|
|
171
|
+
|
|
172
|
+
if system == "Windows":
|
|
173
|
+
# Get all PIDs matching the process name
|
|
174
|
+
pids = find_pids_by_process_name(process_name)
|
|
175
|
+
|
|
176
|
+
if pids:
|
|
177
|
+
# For each PID, find what ports it's using
|
|
178
|
+
for pid in pids:
|
|
179
|
+
out = run(f"netstat -ano | findstr {pid}")
|
|
180
|
+
if out:
|
|
181
|
+
proc_name = get_process_name(pid)
|
|
182
|
+
ports_seen = set()
|
|
183
|
+
|
|
184
|
+
for line in out.strip().split('\n'):
|
|
185
|
+
parts = line.split()
|
|
186
|
+
if len(parts) >= 5 and parts[-1] == pid:
|
|
187
|
+
# Extract port from local address (format: IP:PORT)
|
|
188
|
+
local_addr = parts[1]
|
|
189
|
+
if ':' in local_addr:
|
|
190
|
+
port = local_addr.split(':')[-1]
|
|
191
|
+
if port not in ports_seen:
|
|
192
|
+
ports_seen.add(port)
|
|
193
|
+
state = parts[3] if len(parts) > 3 else "UNKNOWN"
|
|
194
|
+
process_port_map.append((pid, proc_name, port, state))
|
|
195
|
+
|
|
196
|
+
else: # Linux, Ubuntu, macOS
|
|
197
|
+
# Use lsof to find ports by process name
|
|
198
|
+
out = run(f"lsof -i -P -n | grep -i {process_name}")
|
|
199
|
+
if out:
|
|
200
|
+
for line in out.strip().split('\n'):
|
|
201
|
+
parts = line.split()
|
|
202
|
+
if len(parts) >= 9:
|
|
203
|
+
command = parts[0]
|
|
204
|
+
pid = parts[1]
|
|
205
|
+
# Extract port from address (format: *:PORT or IP:PORT)
|
|
206
|
+
address = parts[8]
|
|
207
|
+
if ':' in address:
|
|
208
|
+
port = address.split(':')[-1]
|
|
209
|
+
# Filter out non-LISTEN states if needed
|
|
210
|
+
state = "LISTEN" if "LISTEN" in line else "ESTABLISHED"
|
|
211
|
+
process_port_map.append((pid, command, port, state))
|
|
212
|
+
|
|
213
|
+
return process_port_map
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def kill_pid(pid, silent=False):
|
|
217
|
+
"""Kill process by PID"""
|
|
218
|
+
system = platform.system()
|
|
219
|
+
|
|
220
|
+
if system == "Windows":
|
|
221
|
+
result = run(f"taskkill /PID {pid} /F")
|
|
222
|
+
return result
|
|
223
|
+
else:
|
|
224
|
+
result = run(f"kill -9 {pid}")
|
|
225
|
+
return result if result else "Process killed successfully"
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
def main():
|
|
229
|
+
"""Main entry point"""
|
|
230
|
+
parser = argparse.ArgumentParser(
|
|
231
|
+
description="šŖ kport - Cross-platform port inspector and killer",
|
|
232
|
+
epilog="Examples:\n"
|
|
233
|
+
" kport -i 8080 Inspect port 8080\n"
|
|
234
|
+
" kport -ip node Inspect all processes matching 'node'\n"
|
|
235
|
+
" kport -k 8080 Kill process using port 8080\n"
|
|
236
|
+
" kport -l List all listening ports\n"
|
|
237
|
+
" kport -kp node Kill all processes matching 'node'\n"
|
|
238
|
+
" kport -ka 3000 3001 3002 Kill processes on multiple ports\n",
|
|
239
|
+
formatter_class=argparse.RawDescriptionHelpFormatter
|
|
240
|
+
)
|
|
241
|
+
parser.add_argument("-i", "--inspect", type=int, metavar="PORT",
|
|
242
|
+
help="Inspect which process is using the specified port")
|
|
243
|
+
parser.add_argument("-ip", "--inspect-process", type=str, metavar="NAME",
|
|
244
|
+
help="Inspect all processes matching the given name")
|
|
245
|
+
parser.add_argument("-k", "--kill", type=int, metavar="PORT",
|
|
246
|
+
help="Kill the process using the specified port")
|
|
247
|
+
parser.add_argument("-kp", "--kill-process", type=str, metavar="NAME",
|
|
248
|
+
help="Kill all processes matching the given name")
|
|
249
|
+
parser.add_argument("-ka", "--kill-all", type=int, nargs="+", metavar="PORT",
|
|
250
|
+
help="Kill processes on multiple ports")
|
|
251
|
+
parser.add_argument("-l", "--list", action="store_true",
|
|
252
|
+
help="List all listening ports and their processes")
|
|
253
|
+
parser.add_argument("-v", "--version", action="version", version="kport 1.0.0")
|
|
254
|
+
|
|
255
|
+
args = parser.parse_args()
|
|
256
|
+
|
|
257
|
+
# If no arguments provided, show help
|
|
258
|
+
if not (args.inspect or args.inspect_process or args.kill or args.list or args.kill_process or args.kill_all):
|
|
259
|
+
parser.print_help()
|
|
260
|
+
sys.exit(0)
|
|
261
|
+
|
|
262
|
+
if args.list:
|
|
263
|
+
list_all_ports()
|
|
264
|
+
|
|
265
|
+
if args.inspect_process:
|
|
266
|
+
print(colorize(f"\nš Inspecting processes matching '{args.inspect_process}'...\n", Colors.CYAN + Colors.BOLD))
|
|
267
|
+
|
|
268
|
+
process_info = find_ports_by_process_name(args.inspect_process)
|
|
269
|
+
|
|
270
|
+
if not process_info:
|
|
271
|
+
print(colorize(f"ā No processes found matching '{args.inspect_process}'", Colors.RED))
|
|
272
|
+
else:
|
|
273
|
+
print(colorize(f"Found {len(process_info)} connection(s) for processes matching '{args.inspect_process}':\n", Colors.YELLOW))
|
|
274
|
+
|
|
275
|
+
# Group by PID for better display
|
|
276
|
+
pid_groups = {}
|
|
277
|
+
for pid, proc_name, port, state in process_info:
|
|
278
|
+
if pid not in pid_groups:
|
|
279
|
+
pid_groups[pid] = {'name': proc_name, 'ports': []}
|
|
280
|
+
pid_groups[pid]['ports'].append((port, state))
|
|
281
|
+
|
|
282
|
+
print(colorize(f"{'PID':<10} {'Process':<25} {'Port':<10} {'State':<15}", Colors.BOLD))
|
|
283
|
+
print("ā" * 70)
|
|
284
|
+
|
|
285
|
+
for pid, data in pid_groups.items():
|
|
286
|
+
proc_name = data['name']
|
|
287
|
+
ports = data['ports']
|
|
288
|
+
|
|
289
|
+
# Print first port
|
|
290
|
+
if ports:
|
|
291
|
+
port, state = ports[0]
|
|
292
|
+
print(f"{colorize(pid, Colors.CYAN):<19} {proc_name:<25} {port:<10} {state:<15}")
|
|
293
|
+
|
|
294
|
+
# Print additional ports for same PID
|
|
295
|
+
for port, state in ports[1:]:
|
|
296
|
+
print(f"{'':<10} {'':<25} {port:<10} {state:<15}")
|
|
297
|
+
|
|
298
|
+
print(colorize(f"\nā Total processes found: {len(pid_groups)}", Colors.GREEN))
|
|
299
|
+
print(colorize(f"ā Total connections: {len(process_info)}", Colors.GREEN))
|
|
300
|
+
|
|
301
|
+
if args.kill_process:
|
|
302
|
+
print(colorize(f"\nšŖ Killing all processes matching '{args.kill_process}'...\n", Colors.CYAN + Colors.BOLD))
|
|
303
|
+
|
|
304
|
+
pids = find_pids_by_process_name(args.kill_process)
|
|
305
|
+
if not pids:
|
|
306
|
+
print(colorize(f"ā No processes found matching '{args.kill_process}'", Colors.RED))
|
|
307
|
+
else:
|
|
308
|
+
print(colorize(f"Found {len(pids)} process(es) matching '{args.kill_process}':", Colors.YELLOW))
|
|
309
|
+
print("ā" * 50)
|
|
310
|
+
|
|
311
|
+
for pid in pids:
|
|
312
|
+
proc_name = get_process_name(pid)
|
|
313
|
+
print(colorize(f" PID {pid}: {proc_name}", Colors.WHITE))
|
|
314
|
+
|
|
315
|
+
# Ask for confirmation
|
|
316
|
+
try:
|
|
317
|
+
confirm = input(colorize(f"\nAre you sure you want to kill {len(pids)} process(es)? (y/N): ", Colors.MAGENTA))
|
|
318
|
+
if confirm.lower() not in ['y', 'yes']:
|
|
319
|
+
print(colorize("Operation cancelled.", Colors.YELLOW))
|
|
320
|
+
sys.exit(0)
|
|
321
|
+
except KeyboardInterrupt:
|
|
322
|
+
print(colorize("\n\nOperation cancelled.", Colors.YELLOW))
|
|
323
|
+
sys.exit(0)
|
|
324
|
+
|
|
325
|
+
# Kill all processes
|
|
326
|
+
killed_count = 0
|
|
327
|
+
for pid in pids:
|
|
328
|
+
result = kill_pid(pid, silent=True)
|
|
329
|
+
if result or "SUCCESS" in str(result) or "killed" in str(result).lower():
|
|
330
|
+
killed_count += 1
|
|
331
|
+
print(colorize(f"ā Killed PID {pid}", Colors.GREEN))
|
|
332
|
+
else:
|
|
333
|
+
print(colorize(f"ā Failed to kill PID {pid}", Colors.RED))
|
|
334
|
+
|
|
335
|
+
print(colorize(f"\nā Successfully killed {killed_count}/{len(pids)} process(es)", Colors.GREEN + Colors.BOLD))
|
|
336
|
+
|
|
337
|
+
if args.kill_all:
|
|
338
|
+
print(colorize(f"\nšŖ Killing processes on {len(args.kill_all)} port(s)...\n", Colors.CYAN + Colors.BOLD))
|
|
339
|
+
|
|
340
|
+
# Validate all ports first
|
|
341
|
+
for port in args.kill_all:
|
|
342
|
+
validate_port(port)
|
|
343
|
+
|
|
344
|
+
# Find all PIDs
|
|
345
|
+
port_pid_map = {}
|
|
346
|
+
for port in args.kill_all:
|
|
347
|
+
pid, info = find_pid(port)
|
|
348
|
+
if pid:
|
|
349
|
+
port_pid_map[port] = (pid, info)
|
|
350
|
+
|
|
351
|
+
if not port_pid_map:
|
|
352
|
+
print(colorize(f"ā No processes found on any of the specified ports", Colors.RED))
|
|
353
|
+
else:
|
|
354
|
+
print(colorize(f"Found processes on {len(port_pid_map)} port(s):", Colors.YELLOW))
|
|
355
|
+
print("ā" * 50)
|
|
356
|
+
|
|
357
|
+
for port, (pid, info) in port_pid_map.items():
|
|
358
|
+
proc_name = get_process_name(pid)
|
|
359
|
+
print(colorize(f" Port {port}: PID {pid} ({proc_name})", Colors.WHITE))
|
|
360
|
+
|
|
361
|
+
# Ask for confirmation
|
|
362
|
+
try:
|
|
363
|
+
confirm = input(colorize(f"\nAre you sure you want to kill {len(port_pid_map)} process(es)? (y/N): ", Colors.MAGENTA))
|
|
364
|
+
if confirm.lower() not in ['y', 'yes']:
|
|
365
|
+
print(colorize("Operation cancelled.", Colors.YELLOW))
|
|
366
|
+
sys.exit(0)
|
|
367
|
+
except KeyboardInterrupt:
|
|
368
|
+
print(colorize("\n\nOperation cancelled.", Colors.YELLOW))
|
|
369
|
+
sys.exit(0)
|
|
370
|
+
|
|
371
|
+
# Kill all processes
|
|
372
|
+
killed_count = 0
|
|
373
|
+
for port, (pid, info) in port_pid_map.items():
|
|
374
|
+
result = kill_pid(pid, silent=True)
|
|
375
|
+
if result or "SUCCESS" in str(result) or "killed" in str(result).lower():
|
|
376
|
+
killed_count += 1
|
|
377
|
+
print(colorize(f"ā Killed process on port {port} (PID {pid})", Colors.GREEN))
|
|
378
|
+
else:
|
|
379
|
+
print(colorize(f"ā Failed to kill process on port {port} (PID {pid})", Colors.RED))
|
|
380
|
+
|
|
381
|
+
print(colorize(f"\nā Successfully killed {killed_count}/{len(port_pid_map)} process(es)", Colors.GREEN + Colors.BOLD))
|
|
382
|
+
print(colorize(f"Ports freed: {', '.join(map(str, port_pid_map.keys()))}", Colors.GREEN))
|
|
383
|
+
|
|
384
|
+
if args.inspect:
|
|
385
|
+
validate_port(args.inspect)
|
|
386
|
+
print(colorize(f"\nš Inspecting port {args.inspect}...\n", Colors.CYAN + Colors.BOLD))
|
|
387
|
+
|
|
388
|
+
pid, info = find_pid(args.inspect)
|
|
389
|
+
if not pid:
|
|
390
|
+
print(colorize(f"ā No process found using port {args.inspect}", Colors.RED))
|
|
391
|
+
else:
|
|
392
|
+
print(colorize(f"ā Port {args.inspect} is being used by PID {pid}", Colors.GREEN + Colors.BOLD))
|
|
393
|
+
print(colorize("\nProcess Information:", Colors.YELLOW))
|
|
394
|
+
print("ā" * 50)
|
|
395
|
+
print(info)
|
|
396
|
+
|
|
397
|
+
if args.kill:
|
|
398
|
+
validate_port(args.kill)
|
|
399
|
+
print(colorize(f"\nšŖ Attempting to kill process on port {args.kill}...\n", Colors.CYAN + Colors.BOLD))
|
|
400
|
+
|
|
401
|
+
pid, info = find_pid(args.kill)
|
|
402
|
+
if not pid:
|
|
403
|
+
print(colorize(f"ā No process found using port {args.kill}", Colors.RED))
|
|
404
|
+
else:
|
|
405
|
+
print(colorize(f"Found PID {pid} using port {args.kill}", Colors.YELLOW))
|
|
406
|
+
|
|
407
|
+
# Show process info before killing
|
|
408
|
+
if info:
|
|
409
|
+
print(colorize("\nProcess to be terminated:", Colors.YELLOW))
|
|
410
|
+
print(info)
|
|
411
|
+
|
|
412
|
+
# Ask for confirmation
|
|
413
|
+
try:
|
|
414
|
+
confirm = input(colorize("\nAre you sure you want to kill this process? (y/N): ", Colors.MAGENTA))
|
|
415
|
+
if confirm.lower() not in ['y', 'yes']:
|
|
416
|
+
print(colorize("Operation cancelled.", Colors.YELLOW))
|
|
417
|
+
sys.exit(0)
|
|
418
|
+
except KeyboardInterrupt:
|
|
419
|
+
print(colorize("\n\nOperation cancelled.", Colors.YELLOW))
|
|
420
|
+
sys.exit(0)
|
|
421
|
+
|
|
422
|
+
result = kill_pid(pid)
|
|
423
|
+
if result:
|
|
424
|
+
print(colorize(f"\nā Successfully killed process {pid}", Colors.GREEN + Colors.BOLD))
|
|
425
|
+
if "SUCCESS" in result or "killed" in result.lower():
|
|
426
|
+
print(colorize(f"Port {args.kill} is now free.", Colors.GREEN))
|
|
427
|
+
else:
|
|
428
|
+
print(colorize(f"\nā Failed to kill process {pid}", Colors.RED))
|
|
429
|
+
print(colorize("You may need administrator/sudo privileges.", Colors.YELLOW))
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
if __name__ == "__main__":
|
|
433
|
+
try:
|
|
434
|
+
main()
|
|
435
|
+
except KeyboardInterrupt:
|
|
436
|
+
print(colorize("\n\nOperation cancelled by user.", Colors.YELLOW))
|
|
437
|
+
sys.exit(0)
|
|
438
|
+
except Exception as e:
|
|
439
|
+
print(colorize(f"\nUnexpected error: {e}", Colors.RED))
|
|
440
|
+
sys.exit(1)
|