使用win32api GetTcpTable 查找本地空闲端口号
思路:
先查找本地占用端口号集合,再从想要得端口集合里面排除查找。
先上官方demo:
// Need to link with Iphlpapi.lib and Ws2_32.lib
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
/* Note: could also use malloc() and free() */
int main()
{
// Declare and initialize variables
PMIB_TCPTABLE pTcpTable;
DWORD dwSize = 0;
DWORD dwRetVal = 0;
char szLocalAddr[128];
char szRemoteAddr[128];
struct in_addr IpAddr;
int i;
pTcpTable = (MIB_TCPTABLE *) MALLOC(sizeof (MIB_TCPTABLE));
if (pTcpTable == NULL) {
printf("Error allocating memory\n");
return 1;
}
dwSize = sizeof (MIB_TCPTABLE);
// Make an initial call to GetTcpTable to get the necessary size into the dwSize variable
if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)) ==
ERROR_INSUFFICIENT_BUFFER) {
FREE(pTcpTable);
pTcpTable = (MIB_TCPTABLE *) MALLOC(dwSize);
if (pTcpTable == NULL) {
printf("Error allocating memory\n");
return 1;
}
}
// Make a second call to GetTcpTable to get the actual data we require
if ((dwRetVal = GetTcpTable(pTcpTable, &dwSize, TRUE)) == NO_ERROR) {
printf("\tNumber of entries: %d\n", (int) pTcpTable->dwNumEntries);
for (i = 0; i < (int) pTcpTable->dwNumEntries; i++) {
IpAddr.S_un.S_addr = (u_long) pTcpTable->table[i].dwLocalAddr;
strcpy_s(szLocalAddr, sizeof (szLocalAddr), inet_ntoa(IpAddr));
IpAddr.S_un.S_addr = (u_long) pTcpTable->table[i].dwRemoteAddr;
strcpy_s(szRemoteAddr, sizeof (szRemoteAddr), inet_ntoa(IpAddr));
//可以根据端口号得状态去筛选
printf("\n\tTCP[%d] State: %ld - ", i,
pTcpTable->table[i].dwState);
switch (pTcpTable->table[i].dwState) {
case MIB_TCP_STATE_CLOSED:
printf("CLOSED\n");
break;
case MIB_TCP_STATE_LISTEN:
printf("LISTEN\n");
break;
case MIB_TCP_STATE_SYN_SENT:
printf("SYN-SENT\n");
break;
case MIB_TCP_STATE_SYN_RCVD:
printf("SYN-RECEIVED\n");
break;
case MIB_TCP_STATE_ESTAB:
printf("ESTABLISHED\n");
break;
case MIB_TCP_STATE_FIN_WAIT1:
printf("FIN-WAIT-1\n");
break;
case MIB_TCP_STATE_FIN_WAIT2:
printf("FIN-WAIT-2 \n");
break;
case MIB_TCP_STATE_CLOSE_WAIT:
printf("CLOSE-WAIT\n");
break;
case MIB_TCP_STATE_CLOSING:
printf("CLOSING\n");
break;
case MIB_TCP_STATE_LAST_ACK:
printf("LAST-ACK\n");
break;
case MIB_TCP_STATE_TIME_WAIT:
printf("TIME-WAIT\n");
break;
case MIB_TCP_STATE_DELETE_TCB:
printf("DELETE-TCB\n");
break;
default:
printf("UNKNOWN dwState value\n");
break;
}
printf("\tTCP[%d] Local Addr: %s\n", i, szLocalAddr);
printf("\tTCP[%d] Local Port: %d \n", i,
ntohs((u_short)pTcpTable->table[i].dwLocalPort));
printf("\tTCP[%d] Remote Addr: %s\n", i, szRemoteAddr);
printf("\tTCP[%d] Remote Port: %d\n", i,
ntohs((u_short)pTcpTable->table[i].dwRemotePort));
}
} else {
printf("\tGetTcpTable failed with %d\n", dwRetVal);
FREE(pTcpTable);
return 1;
}
if (pTcpTable != NULL) {
FREE(pTcpTable);
pTcpTable = NULL;
}
return 0;
}
获取已占用端口号集合
#include <winsock2.h>
#include <ws2tcpip.h>
#include <iphlpapi.h>
#include <stdio.h>
#pragma comment(lib, "iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")
#define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x))
#define FREE(x) HeapFree(GetProcessHeap(), 0, (x))
std::vector<uint16_t> GetAllTcpConnectionsPort()
{
std::vector<uint16_t> vPorts;
DWORD size = sizeof(MIB_TCPTABLE);
PMIB_TCPTABLE pTcpTable = (PMIB_TCPTABLE)MALLOC(sizeof(MIB_TCPTABLE));
if (pTcpTable == NULL) {
std::cout << "Error allocating memory" << std::endl;
return vPorts;
}
DWORD dwRetVal = 0;
// Make an initial call to GetTcpTable to get the necessary size into the dwSize variable
if ((dwRetVal = GetTcpTable(pTcpTable, &size, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {
FREE(pTcpTable);
pTcpTable = nullptr;
pTcpTable = (PMIB_TCPTABLE)MALLOC(size);
if (pTcpTable == NULL) {
std::cout << "Error allocating memory" << std::endl;
return vPorts;
}
}
// Make a second call to GetTcpTable to get the actual data we require
char szLocalAddr[128] = { 0 };
char szRemoteAddr[128] = { 0 };
struct in_addr IpAddr, remoteAddr;
if ((dwRetVal = GetTcpTable(pTcpTable, &size, TRUE)) == NO_ERROR) {
std::cout << "\tNumber of entries: " << pTcpTable->dwNumEntries << std::endl;
for (int i = 0; i < (int)pTcpTable->dwNumEntries; i++) {
vPorts.push_back(ntohs(u_short(pTcpTable->table[i].dwLocalPort)));
vPorts.push_back(ntohs(u_short(pTcpTable->table[i].dwRemotePort)));
#if 0
uint16_t localPort = ntohs(u_short(pTcpTable->table[i].dwLocalPort));
uint16_t remotePort = ntohs(u_short(pTcpTable->table[i].dwRemotePort));
IpAddr.S_un.S_addr = (u_long)pTcpTable->table[i].dwLocalAddr;
strcpy_s(szLocalAddr, sizeof(szLocalAddr), inet_ntoa(IpAddr));
std::cout << "\tTCP[" << i << "]" << " Local Addr: " << std::string(szLocalAddr) << ":" << localPort << std::endl;
remoteAddr.S_un.S_addr = (u_long)pTcpTable->table[i].dwRemoteAddr;
strcpy_s(szRemoteAddr, sizeof(szRemoteAddr), inet_ntoa(remoteAddr));
std::cout << "\tTCP[" << i << "]" << " Remote Addr: " << szRemoteAddr << ":" << remotePort << std::endl;
#endif
}
}
else {
std::cout << "\tGetTcpTable failed with " << dwRetVal;
FREE(pTcpTable);
pTcpTable = nullptr;
return vPorts;
}
std::sort(vPorts.begin(), vPorts.end());
vPorts.erase(std::unique(vPorts.begin(), vPorts.end()), vPorts.end());
if (pTcpTable) {
FREE(pTcpTable);
pTcpTable = NULL;
}
return vPorts;
}
查找可用得端口号
uint16_t FindAvailableTcpPort(uint16_t begin /*= 10011*/, uint16_t end /*= 65535*/)
{
auto vec = GetAllTcpConnectionsPort();
for (uint16_t port = begin; port != end; ++port)
if (!std::binary_search(std::begin(vec), std::end(vec), port))
return port;
return 0;
}
莫名得异常
当总是在奇奇怪怪得地方出现错误,比如输出异常,vector入栈异常,或者其他地方出现偶先异常,并且提示系统库内存异常中断,先排除代码使用内存问题(数组长度不够,野指针,未初始化数据,重复析构等),然后一定要看调用系统api是不是给错了参数导致内存分配不够,然后产生一系列得内存访问权限错误等。
0xC0000005: 这是一个特定的异常代码,通常与内存访问违规有关。在Windows中,这个错误代码通常表示“访问冲突”,也就是程序试图访问一个它没有权限访问的内存地址。
if ((dwRetVal = GetTcpTable(pTcpTable, &size, TRUE)) == ERROR_INSUFFICIENT_BUFFER) {
FREE(pTcpTable);
pTcpTable = nullptr;
//pTcpTable = (PMIB_TCPTABLE)MALLOC(sizeof(MIB_TCPTABLE)); //错误分配导致后面内存错误
//第一次调用提示内存分配空间不足错误,这次要分配函数返回得足额空间大小,也就是size
pTcpTable = (PMIB_TCPTABLE)MALLOC(size); //正确
if (pTcpTable == NULL) {
std::cout << "Error allocating memory" << std::endl;
return vPorts;
}
}