// ============================================================
// FastNetworkMonitor.cpp
// Based on GetExtendedTcpTable - Ultra-fast network monitoring
// No Chinese characters - pure English version
// ============================================================
#include <winsock2.h>
#include <iphlpapi.h>
#include <stdio.h>
#include <windows.h>
#include <psapi.h>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <chrono>
#include <ctime>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#pragma comment(lib, "psapi.lib")
#pragma comment(lib, "kernel32.lib")
using namespace std;
using namespace std::chrono;
// ============================================================
// Constants
// ============================================================
#ifndef AF_INET
#define AF_INET 2
#endif
#ifndef TCP_TABLE_OWNER_PID_ALL
#define TCP_TABLE_OWNER_PID_ALL 5
#endif
#ifndef TCP_TABLE_OWNER_PID_LISTENER
#define TCP_TABLE_OWNER_PID_LISTENER 4
#endif
#ifndef UDP_TABLE_OWNER_PID
#define UDP_TABLE_OWNER_PID 1
#endif
// TCP states
#define MY_TCP_STATE_CLOSED 1
#define MY_TCP_STATE_LISTEN 2
#define MY_TCP_STATE_SYN_SENT 3
#define MY_TCP_STATE_SYN_RCVD 4
#define MY_TCP_STATE_ESTAB 5
#define MY_TCP_STATE_FIN_WAIT1 6
#define MY_TCP_STATE_FIN_WAIT2 7
#define MY_TCP_STATE_CLOSE_WAIT 8
#define MY_TCP_STATE_CLOSING 9
#define MY_TCP_STATE_TIME_WAIT 10
#define MY_TCP_STATE_DELETE_TCB 11
// ============================================================
// Data Structures
// ============================================================
struct NetworkConnection {
string Protocol;
string LocalAddr;
DWORD LocalPort;
string RemoteAddr;
DWORD RemotePort;
string State;
DWORD PID;
string ProcessName;
long long Timestamp;
string GetKey() const {
char buffer[512];
sprintf_s(buffer, sizeof(buffer), "%s|%s:%lu|%s:%lu",
Protocol.c_str(), LocalAddr.c_str(), LocalPort,
RemoteAddr.c_str(), RemotePort);
return string(buffer);
}
};
// ============================================================
// Global Variables
// ============================================================
map<string, NetworkConnection> g_previousConnections;
long long g_eventCount = 0;
long long g_pollCount = 0;
// ============================================================
// Windows API Declarations
// ============================================================
typedef int (WINAPI* PGetExtendedTcpTable)(
PVOID pTcpTable,
PDWORD pdwSize,
BOOL bOrder,
ULONG ulAf,
ULONG TableClass,
ULONG Reserved
);
typedef int (WINAPI* PGetExtendedUdpTable)(
PVOID pUdpTable,
PDWORD pdwSize,
BOOL bOrder,
ULONG ulAf,
ULONG TableClass,
ULONG Reserved
);
static PGetExtendedTcpTable pGetExtendedTcpTable = NULL;
static PGetExtendedUdpTable pGetExtendedUdpTable = NULL;
// Initialize API function pointers
void InitializeAPIFunctions() {
HMODULE hIphlpapi = LoadLibraryA("iphlpapi.dll");
if (hIphlpapi) {
pGetExtendedTcpTable = (PGetExtendedTcpTable)GetProcAddress(
hIphlpapi, "GetExtendedTcpTable");
pGetExtendedUdpTable = (PGetExtendedUdpTable)GetProcAddress(
hIphlpapi, "GetExtendedUdpTable");
}
}
// ============================================================
// Utility Functions
// ============================================================
string FormatIPAddress(DWORD ipAddr) {
unsigned char* bytes = (unsigned char*)&ipAddr;
char buffer[16];
sprintf_s(buffer, sizeof(buffer), "%u.%u.%u.%u",
bytes[0], bytes[1], bytes[2], bytes[3]);
return string(buffer);
}
string GetTcpStateName(DWORD state) {
switch (state) {
case MY_TCP_STATE_CLOSED: return "CLOSED";
case MY_TCP_STATE_LISTEN: return "LISTEN";
case MY_TCP_STATE_SYN_SENT: return "SYN_SENT";
case MY_TCP_STATE_SYN_RCVD: return "SYN_RCVD";
case MY_TCP_STATE_ESTAB: return "ESTAB";
case MY_TCP_STATE_FIN_WAIT1: return "FIN_WAIT1";
case MY_TCP_STATE_FIN_WAIT2: return "FIN_WAIT2";
case MY_TCP_STATE_CLOSE_WAIT: return "CLOSE_WAIT";
case MY_TCP_STATE_CLOSING: return "CLOSING";
case MY_TCP_STATE_TIME_WAIT: return "TIME_WAIT";
case MY_TCP_STATE_DELETE_TCB: return "DELETE_TCB";
default: {
static char buffer[32];
sprintf_s(buffer, sizeof(buffer), "STATE_%lu", state);
return string(buffer);
}
}
}
string GetCurrentTimeString() {
time_t now = time(0);
struct tm timeinfo;
localtime_s(&timeinfo, &now);
char buffer[16];
strftime(buffer, sizeof(buffer), "%H:%M:%S", &timeinfo);
return string(buffer);
}
/*
string GetProcessName(DWORD processId) {
if (processId == 0) return "System";
if (processId == 4) return "System";
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
FALSE,
processId
);
if (!hProcess) {
char buffer[32];
sprintf_s(buffer, sizeof(buffer), "PID:%lu", processId);
return string(buffer);
}
WCHAR szProcessName[MAX_PATH] = L"Unknown";
DWORD cbNeeded = 0;
HMODULE hMods[1024];
if (EnumProcessModules(hProcess, hMods, sizeof(hMods), &cbNeeded)) {
GetModuleBaseNameW(hProcess, hMods[0], szProcessName,
sizeof(szProcessName) / sizeof(WCHAR));
}
char buffer[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, szProcessName, -1, buffer, MAX_PATH, NULL, NULL);
CloseHandle(hProcess);
return string(buffer);
}
*/
string GetProcessName(DWORD processId) {
if (processId == 0 || processId == 4) return "System";
HANDLE hProcess = OpenProcess(
PROCESS_QUERY_LIMITED_INFORMATION, // 权限降低,无需 VM_READ
FALSE,
processId
);
if (!hProcess) {
char buffer[32];
sprintf_s(buffer, sizeof(buffer), "PID:%lu", processId);
return string(buffer);
}
WCHAR szProcessName[MAX_PATH] = L"Unknown";
DWORD dwSize = MAX_PATH;
// 用 QueryFullProcessImageNameW 替代 EnumProcessModules + GetModuleBaseNameW
// 只需 PROCESS_QUERY_LIMITED_INFORMATION,不需要 VM_READ
QueryFullProcessImageNameW(hProcess, 0, szProcessName, &dwSize);
// 只取文件名部分,去掉路径
WCHAR* pName = wcsrchr(szProcessName, L'\\');
if (pName) pName++;
else pName = szProcessName;
char buffer[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0, pName, -1, buffer, MAX_PATH, NULL, NULL);
CloseHandle(hProcess);
return string(buffer);
}
long long GetMemoryUsageMB() {
PROCESS_MEMORY_COUNTERS pmc;
if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
return pmc.WorkingSetSize / (1024 * 1024);
}
return 0;
}
// ============================================================
// Get Network Connections
// ============================================================
vector<NetworkConnection> GetTcpConnections() {
vector<NetworkConnection> connections;
if (!pGetExtendedTcpTable) {
printf("ERROR: GetExtendedTcpTable not initialized\n");
return connections;
}
DWORD dwSize = 0;
DWORD dwRetVal = 0;
// First call: get required buffer size
dwRetVal = pGetExtendedTcpTable(
NULL,
&dwSize,
FALSE,
AF_INET,
TCP_TABLE_OWNER_PID_ALL,
0
);
if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
return connections;
}
// Allocate buffer
PMIB_TCPTABLE_OWNER_PID pTcpTable =
(PMIB_TCPTABLE_OWNER_PID)malloc(dwSize);
if (pTcpTable == NULL) {
return connections;
}
// Second call: get TCP table
dwRetVal = pGetExtendedTcpTable(
(PVOID)pTcpTable,
&dwSize,
FALSE,
AF_INET,
TCP_TABLE_OWNER_PID_ALL,
0
);
if (dwRetVal == NO_ERROR) {
for (DWORD i = 0; i < pTcpTable->dwNumEntries; i++) {
MIB_TCPROW_OWNER_PID row = pTcpTable->table[i];
NetworkConnection conn;
conn.Protocol = "TCP";
conn.LocalAddr = FormatIPAddress(row.dwLocalAddr);
conn.LocalPort = ntohs((unsigned short)row.dwLocalPort);
conn.RemoteAddr = FormatIPAddress(row.dwRemoteAddr);
conn.RemotePort = ntohs((unsigned short)row.dwRemotePort);
conn.State = GetTcpStateName(row.dwState);
conn.PID = row.dwOwningPid;
conn.ProcessName = GetProcessName(row.dwOwningPid);
conn.Timestamp = (long long)time(0);
connections.push_back(conn);
}
}
free(pTcpTable);
return connections;
}
vector<NetworkConnection> GetUdpConnections() {
vector<NetworkConnection> connections;
if (!pGetExtendedUdpTable) {
printf("ERROR: GetExtendedUdpTable not initialized\n");
return connections;
}
DWORD dwSize = 0;
DWORD dwRetVal = 0;
// First call: get required buffer size
dwRetVal = pGetExtendedUdpTable(
NULL,
&dwSize,
FALSE,
AF_INET,
UDP_TABLE_OWNER_PID,
0
);
if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
return connections;
}
// Allocate buffer
PMIB_UDPTABLE_OWNER_PID pUdpTable =
(PMIB_UDPTABLE_OWNER_PID)malloc(dwSize);
if (pUdpTable == NULL) {
return connections;
}
// Second call: get UDP table
dwRetVal = pGetExtendedUdpTable(
(PVOID)pUdpTable,
&dwSize,
FALSE,
AF_INET,
UDP_TABLE_OWNER_PID,
0
);
if (dwRetVal == NO_ERROR) {
for (DWORD i = 0; i < pUdpTable->dwNumEntries; i++) {
MIB_UDPROW_OWNER_PID row = pUdpTable->table[i];
NetworkConnection conn;
conn.Protocol = "UDP";
conn.LocalAddr = FormatIPAddress(row.dwLocalAddr);
conn.LocalPort = ntohs((unsigned short)row.dwLocalPort);
conn.RemoteAddr = "0.0.0.0";
conn.RemotePort = 0;
conn.State = "BOUND";
conn.PID = row.dwOwningPid;
conn.ProcessName = GetProcessName(row.dwOwningPid);
conn.Timestamp = (long long)time(0);
connections.push_back(conn);
}
}
free(pUdpTable);
return connections;
}
vector<NetworkConnection> GetTcpListeners() {
vector<NetworkConnection> connections;
if (!pGetExtendedTcpTable) {
return connections;
}
DWORD dwSize = 0;
DWORD dwRetVal = 0;
dwRetVal = pGetExtendedTcpTable(
NULL,
&dwSize,
FALSE,
AF_INET,
TCP_TABLE_OWNER_PID_LISTENER,
0
);
if (dwRetVal != ERROR_INSUFFICIENT_BUFFER) {
return connections;
}
PMIB_TCPTABLE_OWNER_PID pTcpTable =
(PMIB_TCPTABLE_OWNER_PID)malloc(dwSize);
if (pTcpTable == NULL) {
return connections;
}
dwRetVal = pGetExtendedTcpTable(
(PVOID)pTcpTable,
&dwSize,
FALSE,
AF_INET,
TCP_TABLE_OWNER_PID_LISTENER,
0
);
if (dwRetVal == NO_ERROR) {
for (DWORD i = 0; i < pTcpTable->dwNumEntries; i++) {
MIB_TCPROW_OWNER_PID row = pTcpTable->table[i];
NetworkConnection conn;
conn.Protocol = "TCP_LISTEN";
conn.LocalAddr = FormatIPAddress(row.dwLocalAddr);
conn.LocalPort = ntohs((unsigned short)row.dwLocalPort);
conn.RemoteAddr = "0.0.0.0";
conn.RemotePort = 0;
conn.State = "LISTEN";
conn.PID = row.dwOwningPid;
conn.ProcessName = GetProcessName(row.dwOwningPid);
conn.Timestamp = (long long)time(0);
connections.push_back(conn);
}
}
free(pTcpTable);
return connections;
}
// ============================================================
// Print Functions
// ============================================================
void SetConsoleColor(int color) {
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), color);
}
void PrintHeader() {
SetConsoleColor(11); // Cyan
printf("\n");
printf("============================================================================\n");
printf(" GetExtendedTcpTable - Ultra-fast Network Monitor v1.0\n");
printf(" User-mode only, No driver required\n");
printf("============================================================================\n");
printf("\n");
SetConsoleColor(7); // White
}
void PrintTableHeader() {
SetConsoleColor(14); // Yellow
printf("Time | Protocol | Local Address | Remote Address | State | PID | Process\n");
printf("─────────────────────────────────────────────────────────────────────────────────────────────────────\n");
SetConsoleColor(7);
}
void PrintConnection(const NetworkConnection& conn) {
printf("%s | ", GetCurrentTimeString().c_str());
printf("%-8s | ", conn.Protocol.c_str());
char localStr[32], remoteStr[32];
sprintf_s(localStr, sizeof(localStr), "%s:%lu", conn.LocalAddr.c_str(), conn.LocalPort);
sprintf_s(remoteStr, sizeof(remoteStr), "%s:%lu", conn.RemoteAddr.c_str(), conn.RemotePort);
printf("%-20s | ", localStr);
printf("%-20s | ", remoteStr);
printf("%-8s | ", conn.State.c_str());
printf("%-5lu | ", conn.PID);
printf("%s\n", conn.ProcessName.c_str());
}
void PrintStatistics(int connectionCount, double avgTimeMs) {
SetConsoleColor(10); // Green
printf("\n[STATS] Poll#%lld | Connections:%d | AvgTime:%.2fms | Memory:%lldMB | Events:%lld\n",
g_pollCount, connectionCount, avgTimeMs, GetMemoryUsageMB(), g_eventCount);
SetConsoleColor(7);
printf("\n");
}
// ============================================================
// Monitor Function
// ============================================================
void MonitorNetwork(int intervalSeconds = 1) {
PrintHeader();
printf("Starting network monitor, interval: %d seconds\n", intervalSeconds);
printf("Listening for TCP/UDP connection changes...\n");
printf("Press Ctrl+C to stop\n\n");
PrintTableHeader();
long long totalTimeMs = 0;
while (true) {
auto loopStart = high_resolution_clock::now();
g_pollCount++;
// Get all connections
auto tcpConns = GetTcpConnections();
auto udpConns = GetUdpConnections();
auto listenerConns = GetTcpListeners();
// Merge all connections
map<string, NetworkConnection> currentConnections;
for (const auto& conn : tcpConns) {
currentConnections[conn.GetKey()] = conn;
}
for (const auto& conn : udpConns) {
currentConnections[conn.GetKey()] = conn;
}
for (const auto& conn : listenerConns) {
currentConnections[conn.GetKey()] = conn;
}
// Detect new connections
for (const auto& pair : currentConnections) {
if (g_previousConnections.find(pair.first) == g_previousConnections.end()) {
g_eventCount++;
SetConsoleColor(10); // Green
printf("[+] ");
SetConsoleColor(7);
PrintConnection(pair.second);
}
}
// Detect closed connections
for (const auto& pair : g_previousConnections) {
if (currentConnections.find(pair.first) == currentConnections.end()) {
g_eventCount++;
SetConsoleColor(12); // Red
printf("[-] ");
SetConsoleColor(7);
PrintConnection(pair.second);
}
}
// Update cache
g_previousConnections = currentConnections;
auto loopEnd = high_resolution_clock::now();
long long loopTimeMs = duration_cast<milliseconds>(loopEnd - loopStart).count();
totalTimeMs += loopTimeMs;
// Print stats every 5 polls
if (g_pollCount % 5 == 0) {
double avgTimeMs = (double)totalTimeMs / g_pollCount;
PrintStatistics((int)currentConnections.size(), avgTimeMs);
PrintTableHeader();
}
// Sleep until next interval
long long sleepMs = max(0LL, (long long)intervalSeconds * 1000 - loopTimeMs);
if (sleepMs > 0) {
Sleep((DWORD)sleepMs);
}
}
}
// ============================================================
// Performance Test
// ============================================================
void RunPerformanceBenchmark() {
SetConsoleColor(11); // Cyan
printf("\n====================================================================\n");
printf(" GetExtendedTcpTable Performance Test\n");
printf("====================================================================\n\n");
SetConsoleColor(7);
printf("Running performance test with 20 iterations...\n\n");
long long totalTimeMs = 0;
int totalConnections = 0;
int iterations = 20;
for (int i = 0; i < iterations; i++) {
auto start = high_resolution_clock::now();
auto tcpConns = GetTcpConnections();
auto udpConns = GetUdpConnections();
int connCount = (int)(tcpConns.size() + udpConns.size());
totalConnections = connCount;
auto end = high_resolution_clock::now();
long long timeMs = duration_cast<milliseconds>(end - start).count();
totalTimeMs += timeMs;
printf("Iteration #%-2d: %3lldms, Connections: %d\n", i + 1, timeMs, connCount);
}
double avgTimeMs = (double)totalTimeMs / iterations;
SetConsoleColor(10); // Green
printf("\nPerformance Test Results:\n\n");
printf(" Total Connections: %d\n", totalConnections);
printf(" Iterations: %d\n", iterations);
printf(" Total Time: %lld ms\n", totalTimeMs);
printf(" Average Time: %.2f ms\n", avgTimeMs);
printf(" Memory Usage: %lld MB\n\n", GetMemoryUsageMB());
printf("Performance Rating:\n");
if (avgTimeMs < 50) {
printf(" ***** EXCELLENT (< 50ms) *****\n");
}
else if (avgTimeMs < 100) {
printf(" **** VERY GOOD (< 100ms) ****\n");
}
else if (avgTimeMs < 200) {
printf(" *** GOOD (< 200ms) ***\n");
}
else {
printf(" ** FAIR (> 200ms) **\n");
}
printf("\n[OK] Can definitely poll every 1 second!\n\n");
SetConsoleColor(7);
}
// ============================================================
// Show Current Connections
// ============================================================
void ShowCurrentConnections() {
printf("\nFetching all current network connections...\n\n");
auto start = high_resolution_clock::now();
auto tcpConns = GetTcpConnections();
auto udpConns = GetUdpConnections();
auto listenerConns = GetTcpListeners();
auto end = high_resolution_clock::now();
long long timeMs = duration_cast<milliseconds>(end - start).count();
PrintTableHeader();
SetConsoleColor(14);
printf("\n=== TCP Connections (%zu) ===\n", tcpConns.size());
SetConsoleColor(7);
for (const auto& conn : tcpConns) {
PrintConnection(conn);
}
SetConsoleColor(14);
printf("\n=== TCP Listeners (%zu) ===\n", listenerConns.size());
SetConsoleColor(7);
for (const auto& conn : listenerConns) {
PrintConnection(conn);
}
SetConsoleColor(14);
printf("\n=== UDP Bindings (%zu) ===\n", udpConns.size());
SetConsoleColor(7);
for (const auto& conn : udpConns) {
PrintConnection(conn);
}
SetConsoleColor(10);
printf("\nTotal: %zu network connections\n",
tcpConns.size() + udpConns.size() + listenerConns.size());
printf("Time elapsed: %lld ms\n\n", timeMs);
SetConsoleColor(7);
}
// ============================================================
// Main Function
// ============================================================
int main() {
// Initialize API functions
InitializeAPIFunctions();
if (!pGetExtendedTcpTable || !pGetExtendedUdpTable) {
printf("ERROR: Failed to load required API functions\n");
printf("Make sure you are running on Windows XP SP1 or later\n");
return 1;
}
PrintHeader();
printf("Available Operations:\n");
printf(" 1. Performance Test\n");
printf(" 2. Show Current Connections\n");
printf(" 3. Real-time Monitor (1 second interval)\n");
printf(" 4. Real-time Monitor (5 second interval)\n");
printf("\nSelect option (1-4): ");
int choice = 0;
scanf_s("%d", &choice);
switch (choice) {
case 1:
RunPerformanceBenchmark();
printf("Press Enter to exit...");
getchar();
getchar();
break;
case 2:
ShowCurrentConnections();
printf("Press Enter to exit...");
getchar();
getchar();
break;
case 3:
MonitorNetwork(1);
break;
case 4:
MonitorNetwork(5);
break;
default:
printf("Invalid option\n");
}
return 0;
}