It's slow when getting info from single port
This crate is slow when getting info from single port. It uses get_all() inside the get_processes_by_port function.
fn main() {
if let Ok(listeners) = listeners::get_processes_by_port(56240) {
for l in listeners {
println!("{l}");
}
}
}
❯ time cargo run --release
Finished `release` profile [optimized] target(s) in 0.03s
Running `target\release\my-test.exe`
PID: 31108 Process name: sing-box.exe
real 0m 16.51s
user 0m 0.01s
sys 0m 0.03s
16s is unacceptable for me.
for comparing:
// AI generated
#include <iphlpapi.h>
#include <psapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "psapi.lib")
void GetProcessNameAndPidFromPort(DWORD port);
int main(int argc, char *argv[]) {
if (argc != 2) {
printf("Usage: %s <port_number>\n", argv[0]);
return 1;
}
DWORD port = atoi(argv[1]);
GetProcessNameAndPidFromPort(port);
return 0;
}
void GetProcessNameAndPidFromPort(DWORD port) {
PMIB_TCPTABLE_OWNER_PID pTcpTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
int foundTcp = 0;
printf("Searching for port %lu in TCP table...\n", port);
pTcpTable = (PMIB_TCPTABLE_OWNER_PID)malloc(sizeof(MIB_TCPTABLE_OWNER_PID));
if (pTcpTable == NULL) {
printf("Error allocating memory for TCP table.\n");
// Continue to UDP search even if TCP allocation fails
} else {
dwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
if ((dwRetVal = GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET,
TCP_TABLE_OWNER_PID_ALL, 0)) ==
ERROR_INSUFFICIENT_BUFFER) {
free(pTcpTable);
pTcpTable = (PMIB_TCPTABLE_OWNER_PID)malloc(dwSize);
if (pTcpTable == NULL) {
printf("Error re-allocating memory for TCP table.\n");
}
}
if (pTcpTable != NULL && (dwRetVal = GetExtendedTcpTable(
pTcpTable, &dwSize, TRUE, AF_INET,
TCP_TABLE_OWNER_PID_ALL, 0)) == NO_ERROR) {
for (DWORD i = 0; i < pTcpTable->dwNumEntries; i++) {
if (ntohs((u_short)pTcpTable->table[i].dwLocalPort) == port) {
DWORD pid = pTcpTable->table[i].dwOwningPid;
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
TCHAR processName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, NULL, processName, MAX_PATH)) {
printf("Process for TCP port %lu is: %s (PID: %lu)\n", port,
processName, pid);
} else {
printf("Could not get process name for TCP (PID: %lu)\n", pid);
}
CloseHandle(hProcess);
} else {
printf("Could not open process for TCP with PID %lu\n", pid);
}
foundTcp = 1;
break; // Found TCP process, exit loop
}
}
if (!foundTcp) {
printf("No process found using TCP port %lu\n", port);
}
} else if (pTcpTable != NULL) {
printf("GetExtendedTcpTable failed with error code: %d\n", dwRetVal);
}
if (pTcpTable != NULL) {
free(pTcpTable);
pTcpTable = NULL;
}
}
// Now search UDP table
PMIB_UDPTABLE_OWNER_PID pUdpTable;
int foundUdp = 0;
printf("\nSearching for port %lu in UDP table...\n", port);
pUdpTable = (PMIB_UDPTABLE_OWNER_PID)malloc(sizeof(MIB_UDPTABLE_OWNER_PID));
if (pUdpTable == NULL) {
printf("Error allocating memory for UDP table.\n");
return;
}
dwSize = sizeof(MIB_UDPTABLE_OWNER_PID);
if ((dwRetVal = GetExtendedUdpTable(pUdpTable, &dwSize, TRUE, AF_INET,
UDP_TABLE_OWNER_PID, 0)) ==
ERROR_INSUFFICIENT_BUFFER) {
free(pUdpTable);
pUdpTable = (PMIB_UDPTABLE_OWNER_PID)malloc(dwSize);
if (pUdpTable == NULL) {
printf("Error re-allocating memory for UDP table.\n");
return;
}
}
if ((dwRetVal = GetExtendedUdpTable(pUdpTable, &dwSize, TRUE, AF_INET,
UDP_TABLE_OWNER_PID, 0)) == NO_ERROR) {
for (DWORD i = 0; i < pUdpTable->dwNumEntries; i++) {
if (ntohs((u_short)pUdpTable->table[i].dwLocalPort) == port) {
DWORD pid = pUdpTable->table[i].dwOwningPid;
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid);
if (hProcess != NULL) {
TCHAR processName[MAX_PATH];
if (GetModuleFileNameEx(hProcess, NULL, processName, MAX_PATH)) {
printf("Process for UDP port %lu is: %s (PID: %lu)\n", port,
processName, pid);
} else {
printf("Could not get process name for UDP (PID: %lu)\n", pid);
}
CloseHandle(hProcess);
} else {
printf("Could not open process for UDP with PID %lu\n", pid);
}
foundUdp = 1;
break; // Found UDP process, exit loop
}
}
if (!foundUdp) {
printf("No process found using UDP port %lu\n", port);
}
} else {
printf("GetExtendedUdpTable failed with error code: %d\n", dwRetVal);
}
if (pUdpTable != NULL) {
free(pUdpTable);
pUdpTable = NULL;
}
}
# gcc test.c -o find_process.exe -lws2_32 -liphlpapi -lpsapi
❯ time ./find_process.exe 56240
Searching for port 56240 in TCP table...
Process for TCP port 56240 is: ...my-path-to sing-box.exe (PID: 31108)
Searching for port 56240 in UDP table...
No process found using UDP port 56240
real 0m 0.01s
user 0m 0.00s
sys 0m 0.01s
I believe something may be off with how you're running your test. Try measuring the time it takes to directly run the executable file generated by cargo, without using cargo run. This is what I see from my PC:
And since you're using Windows, I've verified it also on Windows:
I think this problem relates to the software running on os:
I ran get_all() on my another windows os and counts the time & opened ports.
> Measure-Command { ./target/release/test_rs.exe }
Days : 0
Hours : 0
Minutes : 0
Seconds : 1
Milliseconds : 985
Ticks : 19857842
TotalDays : 2.29836134259259E-05
TotalHours : 0.000551606722222222
TotalMinutes : 0.0330964033333333
TotalSeconds : 1.9857842
TotalMilliseconds : 1985.7842
❯ cargo r | wc -l
Finished dev profile [unoptimized] target(s) in 0.09s
Running target\debug\test_rs.exe
123
and the result on the issue os (which runs sing-box, it will open a lot of ports):
❯ time ./target/release/my-test.exe | wc -l
real 0m 14.74s
user 0m 0.14s
sys 0m 3.87s
1975
so this crate performs bad when there's a lot of opened ports, i think.
I see, I think you're right.
Well, in theory I could improve the methods to get processes running on a single port, but there's little I can do to improve the time it takes to retrieve them all.
Anyway, thanks for opening this issue making me aware of this.