端口池(C++)
端口池
对齐有点乱,可以复制到自己的IDE自动对齐
PortPool.h
/**************************************************************************
*
* Copyright (C) 2022
* All rights reserved
*
* Filename : WLPortPool.h
* Description : 动态端口已占用完毕的情况下,获取动态端口的函数接口。
* Environment : 由于动态端口资源耗尽,导致主机卫士的curl无法通信,WLPortPool
* 可以在该情况下启动端口扫描的线程,在动态端口不满足()的情况下,创建端口池
* (STU_PORT_POOL)。curl可以在此环境下调用此函数提供的接口获取系统当前可用端口。
*
* Detail : 接口命名空间(WNTPORT)。
* 1. 使用时需先开启端口池扫描线程 createScanPortsThread,该线程需调用 killScanPortsThread 关闭
* 2. 启动线程后,通过全局变量 WNTPORT::g_bFlagGetStaticPort 或者 getPortPoolStatus() 查看当前端口池状态
* 3. 根据第2步的状态选择是否需要获取端口池,如需,调用 getPort()
* Created by mingming.shi on Jan. 24th, 2022
*
*************************************************************************/
#pragma once
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#include <sstream>
#include <windows.h>
#include <WinSock.h>
#include <tcpmib.h>
#include <IPHlpApi.h>
#include <set>
#include "../include/curl/include/curl.h"
#include "..\common\WLNetCommApi.h"
#pragma comment(lib, "WS2_32.lib")
#pragma comment(lib, "IPHlpApi.lib")
#define MAX_PORT_NUM 10 // 默认端口池的数量
#define DEFAULT_START_PORT 1025 // 默认启动端口
#define DEFAULT_STOP_PORT 65535 // 默认终止端口
#define DEFAULT_PORT_RANGE 100 // 默认端口范围
#define DEFAULT_MIN_PORTRANGE 50 // 默认最小端口范围
#define START_STATIC_PORT_FLAG 100 // FLAG:当系统可用动态端口个数小于该值时,启用端口池
/* 端口池结构体 */
typedef struct _PORT_POOL {
UINT nStartPort; // 启动端口
UINT nRange; // 端口范围
bool bEnable; // 保留:当前端口是否可用,用于回调接口时用户自行设置。false表示不可用
_PORT_POOL(UINT nSta = 0, UINT nRan = 0, bool bEn = false):nStartPort(nSta),nRange(nRan),bEnable(bEn){};
bool isContain(UINT uPORT)
{
if ( uPORT >= nStartPort && uPORT < (nStartPort + nRange) )
{
return true;
}
return false;
}
bool isLegal()
{
if( (this->nStartPort + this->nRange) <= DEFAULT_STOP_PORT &&
(this->nStartPort) >= DEFAULT_START_PORT
)
{
return true;
}
return false;
}
bool operator<(const _PORT_POOL& b) const
{
return this->nStartPort == b.nStartPort ? this->nRange <= b.nRange : this->nStartPort < b.nRange;
}
}STU_PORT_POOL, *PSTU_PORT_POOL;
/* (端口池) */
extern std::vector<STU_PORT_POOL> g_stuPortPool;
#ifdef __cplusplus
extern "C" {
#endif
namespace WNTPORT {
extern bool g_bFlagGetStaticPort; // 端口池是否启用。 [true:表示已经启用端口池]
extern bool g_bStartThread; // 端口检测线程是否开启。 [true:表示已经启动端口检测线程]
extern int g_nCurPoint; // 端口池轮询
extern HANDLE g_hEvent; // 端口池检测线程的控制句柄
/* 端口池线程 */
void createScanPortsThread();
/* 杀死线程 */
void killScanPortsThread();
#if 0 /* WLNetCommApi */
#endif
/* 设置当前端口状态 */
void WINAPI setPortIsAvailable(__in STU_PORT_POOL stuPort);
/* 返回一个可用端口和其范围 */
void WINAPI getPort(__out STU_PORT_POOL& stuPort);
/* 返回端口池状态 */
bool WINAPI getPortPoolStatus();
/* 设置 curl 的启动端口和范围 */
int WINAPI setCurlPort(CURL *curl);
/* 设置 socket 的本地端口 */
int WINAPI setSocketPort(SOCKADDR_IN *socket);
}
#ifdef __cplusplus
}
#endif
PortPool.cpp
/**************************************************************************
*
* Copyright (C) 2022 Beijing
* All rights reserved
*
* Filename : WLPortPool.cpp
* Description : 动态端口已占用完毕的情况下,获取动态端口的函数接口实现文件,详看头文件声明
*
* Created by mingming.shi on Jan. 24th, 2022
*
*************************************************************************/
#include "StdAfx.h"
#include "WLPortPool.h"
#include <process.h>
#define STU_MEMBER_NUM 2
#define CMD_RESULT_BUF_SIZE 1024
#define TIME_SCAN_FREQUENCY 1000 * 30
#define CMD_QUERY_DYNAMIC_TCPPORT "netsh int ipv4 show dynamicport tcp"
std::vector<STU_PORT_POOL> g_stuPortPool;
bool WNTPORT::g_bFlagGetStaticPort = false;
bool WNTPORT::g_bStartThread = false;
int WNTPORT::g_nCurPoint = 0;
HANDLE WNTPORT::g_hEvent = NULL;
#if 0 /* 内部函数声明 */
#endif
/************************************************************************/
/* 其他函数声明 2022-1-24 14:33:28 */
/************************************************************************/
// 获取动态端口
int executeCMD(__out char *pChRet);
int getDynamicPortFromstr(__out STU_PORT_POOL& stuDynamicPort);
// 获取当前已占用端口
int getAllTcpConnectionsPort(__out std::set<UINT>& setRet);
// 获取剩余端口
int getFreeDynamicPort(__in STU_PORT_POOL stuDynamicPort, __in std::set<UINT> CurSysUsedPort, __out std::vector<STU_PORT_POOL>& stuFreeDynamicPort);
int getFreeStaticPort(__in STU_PORT_POOL stuDynamicPort, __in std::set<UINT> CurSysUsedPort, __out std::vector<STU_PORT_POOL>& stuFreeStaticPort);
// 更新端口
void updatePort(__in __out std::vector<STU_PORT_POOL>::iterator it);
// 创建端口池
int createPortPool();
// 获取剩余动态端口数量
int getFreeDynamicPortsNum(__out int& nNum);
// 线程:获取系统当前剩余动态端口数量
unsigned int WINAPI scanSysDynamicPortsNum(void* lpParam);
#if 0 /* 对外接口定义 */
#endif
/*
* @fn createScanPortsThread
* @brief 启动端口检测线程,设置 g_bStartThread 句柄控制端口池线程的状态
* @param[in]
* @param[out]
* @return
*
* @detail 调用 killScanPortsThread 关闭端口扫描线程
* @author mingming.shi
* @date 2022-1-27
*/
void WNTPORT::createScanPortsThread()
{
if( false == g_bStartThread )
{
HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, scanSysDynamicPortsNum, 0, 0, NULL);
if (NULL == hThread)
{
WriteError(_T("Create scanSysDynamicPortsNum thread error. [%d]"), GetLastError());
g_bStartThread = false;
return;
}
WriteInfo(_T("Create scanSysDynamicPortsNum thread SUCCESS. "));
g_hEvent = CreateEvent(NULL, TRUE, FALSE, TEXT("PortPool"));
CloseHandle(hThread);
g_bStartThread = true;
}
}
/*
* @fn killScanPortsThread
* @brief 杀死扫描动态端口的线程
* @param[in]
* @param[out]
* @return
*
* @detail
* @author mingming.shi
* @date 2022-1-28
*/
void WNTPORT::killScanPortsThread()
{
SetEvent(g_hEvent);
WriteInfo(_T("LINE [%d] killScanPortsThread"), __LINE__);
return;
}
/*
* @fn getPort
* @brief 返回一个可用端口和其范围(同时供 WLNetCommApi 使用)
* @param[in]
* @param[out] STU_PORT_POOL: 返回一个可用端口,如果调用失败,则修改stuPort中的BEnable为false
* @return 0表示成功;其他表示失败
*
* @detail 依次返回端口池中的端口和范围
* @author mingming.shi
* @date 2022-1-24
*/
void WINAPI WNTPORT::getPort(__out STU_PORT_POOL& stuPort)
{
int iRet = -1;
std::vector<STU_PORT_POOL>::iterator it = g_stuPortPool.begin();
if ( 0 == g_stuPortPool.size() ) // 当前端口池为空
{
iRet = createPortPool();
if (NO_ERROR != iRet)
{
WriteError(_T("LINE [%d] Create Port Pool FAILED!"), __LINE__);
return;
}
}
it = g_stuPortPool.begin();
for (int i = 0; it != g_stuPortPool.end(); it++)
{
if (false == it->isLegal())
{
updatePort(it);
}
if ( true == it->bEnable && // 当前端口可用
true == it->isLegal() && // 当前端口合法
i == g_nCurPoint % 10) // 轮询
{
STU_PORT_POOL stuTemp;
stuTemp = *it;
stuPort.nStartPort = stuTemp.nStartPort;
stuPort.nRange = stuTemp.nRange;
stuPort.bEnable = stuTemp.bEnable;
g_nCurPoint++;
if (g_nCurPoint >= INT_MAX)
{
g_nCurPoint = 0;
}
break;
}
i++;
}
}
/*
* @fn setPortIsAvailable
* @brief 设置当前端口的可用状态(同时供 WLNetCommApi 使用)
* @param[in] STU_PORT_POOL: 需要删除的端口
* @param[out]
* @return
*
* @detail 会根据当前的启动端口和范围在端口池中查找一致的并删除,然后立即更新端口池
* 【改接口保留,但目前未使用】
* @author mingming.shi
* @date 2022-1-24
*/
void WINAPI WNTPORT::setPortIsAvailable(__in STU_PORT_POOL stuPort)
{
std::vector<STU_PORT_POOL>::iterator it = g_stuPortPool.begin();
for (; it != g_stuPortPool.end(); it++)
{
if (it->nStartPort == stuPort.nStartPort &&
it->nRange == stuPort.nRange &&
stuPort.bEnable == false) // 当前端口不可用
{
// g_stuPortPool.erase(it); // 目前不移除
break;
}
}
updatePort(it);
}
/*
* @fn getPortPoolStatus
* @brief 获取端口池启用状态(同时供 WLNetCommApi 使用)
* @param[in]
* @param[out]
* @return true表示已经启用端口池
*
* @detail
* @author mingming.shi
* @date 2022-1-28
*/
bool WINAPI WNTPORT::getPortPoolStatus()
{
return g_bFlagGetStaticPort;
}
/*
* @fn setCurlPort
* @brief 设置Curl的启动端口和范围
* @param[in] curl:需要设置端口的CURL对象
* @param[out] curl:设置了启动端口和范围的CURL对象
* @return 0表示成功;其他表示失败
*
* @detail
* @author mingming.shi
* @date 2022-2-10
*/
int WINAPI WNTPORT::setCurlPort(__in __out CURL *curl)
{
int iRet = 0;
std::set<UINT> CurSysUsedPort;
STU_PORT_POOL stuAllPortRange;
STU_PORT_POOL stuSet2CurlPort;
// 1 获取端口占用情况
iRet = getAllTcpConnectionsPort(CurSysUsedPort);
if(NO_ERROR != iRet)
{
iRet = -1;
goto _END_;
}
// 2 从未占用的端口中获取一个启动地址和范围
stuAllPortRange.nStartPort = DEFAULT_START_PORT;
stuAllPortRange.nRange = DEFAULT_STOP_PORT;
for (UINT nPort = DEFAULT_START_PORT; nPort != DEFAULT_STOP_PORT; ++nPort)
{
if ( CurSysUsedPort.end() == CurSysUsedPort.find(nPort) && true == stuAllPortRange.isContain(nPort) ) // 找到了未使用端口,并且不在动态端口范围内
{
int nRange = 0;
// 遍历当前启动端口的端口范围
do
{
nRange++;
}while (
CurSysUsedPort.end() == CurSysUsedPort.find(nPort + nRange) // 系统未使用
&& nRange < DEFAULT_PORT_RANGE); // 范围小于默认端口范围
stuSet2CurlPort.nStartPort = nPort;
stuSet2CurlPort.nRange = nRange >= DEFAULT_MIN_PORTRANGE ? nRange : DEFAULT_MIN_PORTRANGE;
}
}
// 3 设置curl的启动端口和范围
curl_easy_setopt(curl, CURLOPT_LOCALPORT, stuPort.nStartPort);
curl_easy_setopt(curl, CURLOPT_LOCALPORTRANGE, stuPort.nRange);
iRet = 0;
_END_:
return iRet;
}
/*
* @fn setSocketPort
* @brief 绑定一个本地可用端口到socket
* @param[in] socket:需要绑定本地端口的socket
* @param[out] socket:绑定了本地端口的socket
* @return 0表示成功;其他表示失败
*
* @detail
* @author mingming.shi
* @date 2022-2-10
*/
int WINAPI WNTPORT::setSocketPort(__in __out SOCKADDR_IN *socket)
{
int iRet;
int iBindRet;
SOCKADDR_IN myaddr;
std::set<UINT> CurSysUsedPort;
UINT nPort = DEFAULT_START_PORT;
// 1 获取端口占用情况
iRet = getAllTcpConnectionsPort(CurSysUsedPort);
if(NO_ERROR != iRet)
{
iRet = -1;
goto _END_;
}
// 2 从未占用的端口中获取一个可用端口并设置
for ( nPort != DEFAULT_STOP_PORT; ++nPort)
{
if ( CurSysUsedPort.end() == CurSysUsedPort.find(nPort) && true == stuAllPortRange.isContain(nPort) ) // 找到了未使用端口,并且不在动态端口范围内
{
break;
}
}
// 绑定 nPort 到 sokcet
myaddr.sin_port = htons(nPort);
myaddr.sin_addr.s_addr = INADDR_ANY;
myaddr.sin_family = AF_INET;
iBindRet = bind(m_Socket, (SOCKADDR*)&myaddr, sizeof( struct sockaddr));
if (iBindRet < 0)
{
iRet = -2;
goto _END_;
}
_END_:
return iRet;
}
#if 0 /* 内部函数定义 */
#endif
/*
* @fn CreatPortPool
* @brief 创建端口资源池
* @param[in]
* @param[out]
* @return 0:成功;其他:表示失败
*
* @detail 当系统动态端口使用情况不满足IEG时调用此接口获取静态端口资源池,保存到 g_stuPortPool 变量中
* @author mingming.shi
* @date 2022-1-24
*/
int createPortPool()
{
int iRet = 0;
std::vector<STU_PORT_POOL> stuPortPool; // 保存接口返回的端口范围
std::vector<STU_PORT_POOL> stuFreeDynamicPort; // 保存未被使用端口范围
STU_PORT_POOL stuDynamicPort;
std::set<UINT> CurSysUsedPort;
// 1 获取动态端口状态(起始地址和范围)
iRet = getDynamicPortFromstr(stuDynamicPort);
if(NO_ERROR != iRet)
{
iRet = -1;
goto _END_;
}
// 2 获取端口占用情况
iRet = getAllTcpConnectionsPort(CurSysUsedPort);
if(NO_ERROR != iRet)
{
iRet = -2;
goto _END_;
}
// 3 从默认地址开始查找可用端口范围
iRet = getFreeStaticPort(stuDynamicPort, CurSysUsedPort, stuFreeDynamicPort);
if(NO_ERROR == iRet)
{
g_stuPortPool = stuFreeDynamicPort;
}
iRet = 0;
_END_:
return iRet;
}
/*
* @fn ExecuteCMD
* @brief 执行查询TCP动态端口命令,获取系统动态端口范围
* @param[in]
* @param[out] pChRet: 命令行执行后的输出字符串
* @return 0 表示成功;其他 失败
*
* @detail
* @author mingming.shi
* @date 2022-1-24
*/
static int executeCMD(__out char *pChRet)
{
int iRet = -1;
char buf_ps[CMD_RESULT_BUF_SIZE];
char pChBuf[CMD_RESULT_BUF_SIZE] = { 0 };
FILE *ptr;
strcpy_s(pChBuf, _countof(CMD_QUERY_DYNAMIC_TCPPORT) ,CMD_QUERY_DYNAMIC_TCPPORT);
if ( NULL != (ptr = _popen(pChBuf, "r")) )
{
while (NULL != fgets(buf_ps, sizeof(buf_ps), ptr) )
{
strcat_s(pChRet, _countof(buf_ps), buf_ps);
if (strlen(pChRet) > CMD_RESULT_BUF_SIZE)
{
iRet = -2;
break;
}
}
_pclose(ptr);
ptr = NULL;
iRet = 0; // 处理成功
}
else
{
WriteError(_T("popen %s error\n"), pChBuf);
iRet = -1; // 处理失败
}
return iRet;
}
/*
* @fn getDynamicPortFromstr
* @brief 从cmd命令的输出中获取动态端口的启动地址和范围
* @param[in]
* @param[out] stuDynamicPort: 动态端口的起始地址和范围
* @return 0 表示成功,其他表示失败
*
* @detail 该动态端口为TCP端口
* @author mingming.shi
* @date 2022-1-24
*/
int getDynamicPortFromstr(__out STU_PORT_POOL& stuDynamicPort)
{
int iRet = 0;
size_t nStrLen = 0;
std::string strCmdRet = "";
std::vector<unsigned int> vecNumFromStr;
char chRet[CMD_RESULT_BUF_SIZE] = { 0 };
// 1 执行CMD获取其输出,格式如下
/*
协议 tcp 动态端口范围
---------------------------------
启动端口 : 49152
端口数 : 16384
*/
iRet = executeCMD(chRet);
if ( NO_ERROR != iRet )
{
iRet = -1;
goto _END_;
}
strCmdRet = chRet; // char to string
if(strCmdRet.empty())
{
iRet = -2;
goto _END_;
}
// 2 获取CMD输出中的数字
nStrLen = strCmdRet.length();
for (size_t i = 0; i < nStrLen; i++) {
int CurNum = 0;
bool flag = false;
while ( !(strCmdRet[i] >= '0' && strCmdRet[i] <= '9') && i < nStrLen ) // 遍历到数字
{
i++;
}
while ( (strCmdRet[i] >= '0' && strCmdRet[i] <= '9') && i < nStrLen ) // 遍历到字母
{
flag = true;
CurNum = CurNum * 10 + (strCmdRet[i] - '0');
i++;
}
if (flag)
{
vecNumFromStr.push_back(CurNum);
}
}
if (STU_MEMBER_NUM != vecNumFromStr.size())
{
iRet = -3;
goto _END_;
}
stuDynamicPort.nStartPort = vecNumFromStr[0];
stuDynamicPort.nRange = vecNumFromStr[1];
iRet = 0;
_END_:
return iRet; //集合大小就是不同整数数量
}
/*
* @fn getAllTcpConnectionsPort
* @brief 获取已连接端口数
* @param[in]
* @param[out] ret:已连接端口的set容器
* @return 0 表示执行成功,其他表示失败
*
* @detail
* @author mingming.shi
* @date 2022-1-24
*/
int getAllTcpConnectionsPort(__out std::set<UINT>& setRet)
{
int iRet = 0;
int nNum = 0; // TCP连接的数目
std::set<UINT> setPort;
PMIB_TCPTABLE_OWNER_PID pTcpTable(NULL);
DWORD dwSize(0);
GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
pTcpTable = (MIB_TCPTABLE_OWNER_PID *)new char[dwSize];//重新分配缓冲区
if ( NO_ERROR != GetExtendedTcpTable(pTcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0) )
{
delete pTcpTable;
pTcpTable = NULL;
{
iRet = -1;
goto _END_;
}
}
// TCP连接的数目
nNum = (int)pTcpTable->dwNumEntries;
for (int i = 0; i < nNum; i++)
{
setPort.insert(htons((u_short)pTcpTable->table[i].dwLocalPort));
}
setRet = setPort;
_END_:
if (pTcpTable != NULL)
{
free(pTcpTable);
pTcpTable = NULL;
}
return iRet;
}
/*
* @fn getFreeDynamicPort
* @brief 获取未被占用的动态端口段
* @param[in] stuDynamicPort:系统当前开放的动态端口范围
CurSysUsedPort:系统当前已使用端口
* @param[out] stuFreeStaticPort: 从默认端口开始获取的端口范围
* @return
*
* @detail
* @author mingming.shi
* @date 2022-1-24
*/
int getFreeDynamicPort(__in STU_PORT_POOL stuDynamicPort, __in std::set<UINT> CurSysUsedPort, __out std::vector<STU_PORT_POOL>& stuFreeDynamicPort)
{
int iRet = 0;
UINT nStart = stuDynamicPort.nStartPort;
UINT nEnd = stuDynamicPort.nStartPort + stuDynamicPort.nRange;
for (UINT nPort = nStart; nPort != nEnd; ++nPort)
{
STU_PORT_POOL stuTempPort;
if ( CurSysUsedPort.end() != CurSysUsedPort.find(nPort) ) // 找到了未使用端口
{
int nRange = 0;
// 遍历当前启动端口的端口范围
while ( CurSysUsedPort.end() != CurSysUsedPort.find( nPort + nRange) )
{
nRange++;
}
stuTempPort.nStartPort = nPort;
stuTempPort.nRange = nRange;
}
stuFreeDynamicPort.push_back(stuTempPort);
if (stuFreeDynamicPort.size() > MAX_PORT_NUM)
{
iRet = -1;
goto _END_;
}
}
_END_:
return iRet;
}
/*
* @fn getFreeStaticPort
* @brief 从默认端口开始获取未被系统使用的静态端口和范围
* @param[in] stuDynamicPort:系统当前开放的动态端口范围
CurSysUsedPort:系统当前已使用端口
* @param[out] stuFreeStaticPort: 返回
* @return 0 表示成功,其他表示失败
*
* @detail
* @author mingming.shi
* @date 2022-1-24
*/
int getFreeStaticPort(__in STU_PORT_POOL stuDynamicPort, __in std::set<UINT> CurSysUsedPort, __out std::vector<STU_PORT_POOL>& stuFreeStaticPort)
{
int iRet = -1;
UINT nStart = DEFAULT_START_PORT;
UINT nEnd = DEFAULT_STOP_PORT;
for (UINT nPort = nStart; nPort != nEnd; ++nPort)
{
STU_PORT_POOL stuTempPort;
if ( CurSysUsedPort.end() == CurSysUsedPort.find(nPort) && false == stuDynamicPort.isContain(nPort) ) // 找到了未使用端口,并且不在动态端口范围内
{
int nRange = 0;
// 遍历当前启动端口的端口范围
do
{
nRange++;
}while (
CurSysUsedPort.end() == CurSysUsedPort.find(nPort + nRange) && // 系统未使用
false == stuDynamicPort.isContain(nPort + nRange) && // 不在动态端口范围
nRange < DEFAULT_PORT_RANGE); // 范围小于默认端口范围
stuTempPort.nStartPort = nPort;
stuTempPort.nRange = nRange >= DEFAULT_MIN_PORTRANGE ? nRange : DEFAULT_MIN_PORTRANGE;
stuTempPort.bEnable = true;
// 更新启动端口并检查合法性
nPort += nRange;
nPort = nPort >= DEFAULT_STOP_PORT ? DEFAULT_START_PORT : nPort;
}
stuFreeStaticPort.push_back(stuTempPort);
if (stuFreeStaticPort.size() >= MAX_PORT_NUM) // 只是数组满了而已,仍然返回成功
{
iRet = 0;
goto _END_;
}
}
iRet = 0;
_END_:
return iRet;
}
/*
* @fn getFreeDynamicPortsNum
* @brief 获取剩余动态端口数量
* @param[in]
* @param[out] nNum:系统空闲动态端口数量
* @return 0 表示成功,其他表示失败
*
* @detail
* @author mingming.shi
* @date 2022-1-24
*/
int getFreeDynamicPortsNum(__out int& nNum)
{
int iRet = 0;
int nPortsNum = 0;
STU_PORT_POOL stuDynamicPort;
std::set<UINT> CurSysUsedPort;
std::set<UINT>::iterator it;
// 1 获取动态端口状态(起始地址和范围)
iRet = getDynamicPortFromstr(stuDynamicPort);
if ( NO_ERROR != iRet )
{
iRet = -1;
goto _END_;
}
// 2 获取当前系统端口占用情况
iRet = getAllTcpConnectionsPort(CurSysUsedPort);
if ( NO_ERROR != iRet )
{
iRet = -2;
goto _END_;
}
// 3 统计动态端口个数
for (it = CurSysUsedPort.begin(); it != CurSysUsedPort.end(); it++)
{
if(true == stuDynamicPort.isContain(*it))
{
nPortsNum++;
}
}
nNum = stuDynamicPort.nRange - nPortsNum;
iRet = 0;
_END_:
if (CurSysUsedPort.size())
{
CurSysUsedPort.clear();
}
return iRet;
}
/*
* @fn updatePort
* @brief 端口池更新:更新一个端口到端口池中
* @param[in]
* @param[out]
* @return
*
* @detail
* @author mingming.shi
* @date 2022-1-27
*/
void updatePort(__in __out std::vector<STU_PORT_POOL>::iterator it)
{
UINT nStart = DEFAULT_START_PORT;
UINT nEnd = DEFAULT_STOP_PORT;
STU_PORT_POOL stuDynamicPort;
std::set<UINT> CurSysUsedPort;
std::vector<STU_PORT_POOL>::reverse_iterator itPortPoolEnd = g_stuPortPool.rbegin();
// 1 获取动态端口状态(起始地址和范围)
getDynamicPortFromstr(stuDynamicPort);
// 2 获取端口占用情况
getAllTcpConnectionsPort(CurSysUsedPort);
// 3 更新启动端口,从端口池最后一个端口开始
if (true == itPortPoolEnd->isLegal())
{
nStart = itPortPoolEnd->nStartPort > DEFAULT_START_PORT ? itPortPoolEnd->nStartPort : DEFAULT_START_PORT;
}
else
{
nStart = DEFAULT_START_PORT;
}
// 4 寻找可用端口和范围
for (UINT nPort = nStart; nPort <= DEFAULT_STOP_PORT; ++nPort)
{
STU_PORT_POOL stuTempPort;
if ( CurSysUsedPort.end() != CurSysUsedPort.find(nPort) && false == stuDynamicPort.isContain(nPort) ) // 找到了未使用端口,并且不再动态端口范围内
{
int nRange = 0;
// 遍历当前启动端口的端口范围
while ( CurSysUsedPort.end() != CurSysUsedPort.find(nPort + nRange) && false == stuDynamicPort.isContain(nPort + nRange) )
{
nRange++;
if (nRange >= DEFAULT_PORT_RANGE)
{
break;
}
}
stuTempPort.nStartPort = nPort;
stuTempPort.nRange = nRange;
stuTempPort.bEnable = true;
// 更新启动端口并检查合法性
nPort += nRange;
nPort = nPort >= DEFAULT_STOP_PORT ? DEFAULT_START_PORT : nPort;
}
if (true == stuTempPort.isLegal())
{
it->nStartPort = stuTempPort.nStartPort;
it->nRange = stuTempPort.nRange;
it->bEnable = stuTempPort.bEnable;
}
if (g_stuPortPool.size() > MAX_PORT_NUM)
{
break;
}
}
}
/*
* @fn scanSysDynamicPortsNum
* @brief 扫描系统当前剩余动态端口数量
* @param[in]
* @param[out]
* @return
*
* @detail
* @author mingming.shi
* @date 2022-1-27
*/
unsigned int WINAPI scanSysDynamicPortsNum(void* lpParam)
{
int iRet = -1;
while(1)
{
int nDynamicNum = INT_MAX;
//step1: 执行动态端口扫描流程,获取 启动端口 和 范围
if ( NO_ERROR != getFreeDynamicPortsNum(nDynamicNum) )
{
WriteInfo(_T("LINE [%d] PortPool Get Dynamic Port Number Failed!\n"), __LINE__);
iRet = -1;
goto _END_;
}
//step2:判断当前可用动态端口是否需要启用端口池
if (START_STATIC_PORT_FLAG >= nDynamicNum)
{
// WriteInfo(_T("LINE [%d] PortPool Start Get Static Port!\n"), __LINE__);
iRet = createPortPool();
if (NO_ERROR != iRet)
{
WriteInfo(_T("LINE [%d] PortPool Create Static PortPool FAILED!\n"), __LINE__);
iRet = -2;
goto _END_;//
}
WNTPORT::g_bFlagGetStaticPort = true;
}
else
{
WNTPORT::g_bFlagGetStaticPort = false;
}
//step3: 等待停止线程信号,每30s执行一次
DWORD dwRet = WaitForSingleObject(WNTPORT::g_hEvent, TIME_SCAN_FREQUENCY);
switch (dwRet)
{
case WAIT_OBJECT_0:
// hProcess所代表的进程在 TIME_SCAN_FREQUENCY 秒内结束
iRet = 0;
WNTPORT::g_bStartThread = false;
WNTPORT::g_bFlagGetStaticPort = false; // TODO
WriteInfo(_T("LINE [%d] PortPool killed PortPool SUCCESS!\n"), __LINE__);
goto _END_;
case WAIT_TIMEOUT:
// 等待时间超过5秒,暂不处理
break;
case WAIT_FAILED:
// 函数调用失败,比如传递了一个无效的句柄
WriteError(_T("LINE [%d] PortPool killed PortPool FAILED!\n"), __LINE__);
break;
}
iRet = 0;
}
_END_:
return iRet;
}
本文来自博客园,作者:StimuMing,转载请注明原文链接:https://www.cnblogs.com/fole-del/p/15878920.html