寻找可用端口资源

#include <iostream>
#include <mutex>
#include <atomic>
using namespace std;
#ifdef WIN32
#include <winsock2.h>
#include <WS2tcpip.h>
#pragma comment(lib,"ws2_32.lib")
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/net.h>
#endif

//在服务端经常需要分配端口用来接收其他信息,所以这时就在端口资源中找出可用的端口资源
class CAlloct_port
{
public:
	static CAlloct_port * GetInstance();

	bool GetAvailableTCPPort(const char* ip, unsigned short& port);
	bool GetAvailableUDPPort(const char* ip, unsigned short& port);

	bool SetAllocPortMin(const unsigned int& minport);
	bool SetAllocPortMax(const unsigned int& maxport);
private:
	CAlloct_port();
	~CAlloct_port();

	CAlloct_port(CAlloct_port&) = delete;
	CAlloct_port& operator=(CAlloct_port&) = delete;

private:
	static CAlloct_port* m_Instance;
	static std::mutex m_InstanceLocker;

	unsigned int	m_alloc_min;
	unsigned int	m_alloc_max;
	std::atomic<int> m_lastPort; //防止多线程下出问题
};
#include "CAlloct_port.h"

CAlloct_port* CAlloct_port::m_Instance = nullptr;
std::mutex CAlloct_port::m_InstanceLocker;
CAlloct_port * CAlloct_port::GetInstance()
{
	if (nullptr == m_Instance)
	{
		std::lock_guard<std::mutex> l(m_InstanceLocker);
		if (nullptr == m_Instance)
		{
			m_Instance = new (std::nothrow) CAlloct_port();
			if (nullptr == m_Instance)
			{
				std::cout << __FUNCTION__ << ":" << __LINE__ << "实例化失败" << std::endl;
			}
		}
	}
	return m_Instance;
}

bool CAlloct_port::GetAvailableTCPPort(const char* ip, unsigned short& port)
{
	struct sockaddr_in sSvrAddr;
	memset(&sSvrAddr, 0, sizeof(sSvrAddr));
	sSvrAddr.sin_family = AF_INET;

	//将点分十进制转换为二进制
	if (1 != inet_pton(AF_INET, ip, (void*)&sSvrAddr.sin_addr))
	{
#ifdef WIN32
		printf("inet_pton失败,%d", ::GetLastError());
#else
		::perror(inet_pton失败);
#endif
	}

	//将二进制转换未点分十进制
	//char IPdotdec[20] = {};
	//if (NULL == inet_ntop(AF_INET, (PVOID*)&sSvrAddr.sin_addr, IPdotdec, 20))
	//{
	//	printf("inet_ntop失败1,%d", ::GetLastError());
	//}

	//int listen(int sockfd,int backlog);第二个参数是提示内核监听队列的最大长度,监听队列的长度如何超过backlog
	//服务端将不在会受理新的连接请求,并且客户端会受到ECONNREFUSED的错误信息
	int cycle = 1;
	while (1)
	{
		if (m_lastPort > m_alloc_max)
		{
			++cycle;
			if (cycle >= 2)
			{
				return false;
			}
			m_lastPort = m_alloc_min;
		}
		sSvrAddr.sin_port = htons(m_lastPort);
		SOCKET iSvrFd = socket(AF_INET, SOCK_STREAM, 0);
		if (0 == ::bind(iSvrFd, (struct sockaddr*)&sSvrAddr, sizeof(sSvrAddr)))
		{
			//该端口可用
			port = m_lastPort;
			return true;

		}
#ifdef WIN32
		printf("错误码为:%d",::GetLastError());
		closesocket(iSvrFd);
#else
		close(iSvrFd);
#endif 

		//端口不可用,重新分配
		m_lastPort.fetch_add(1);
	}
	return false;
}
bool CAlloct_port::GetAvailableUDPPort(const char* ip, unsigned short& port)
{
	struct sockaddr_in sSvrAddr;
	memset(&sSvrAddr, 0, sizeof(sSvrAddr));
	sSvrAddr.sin_family = AF_INET;
	if (1 != inet_pton(AF_INET, ip, (void*)&sSvrAddr.sin_addr))
	{
#ifdef WIN32
		printf("inet_pton失败,%d", ::GetLastError());
#else
		::perror(inet_pton失败);
#endif
	}

	//将二进制转换未点分十进制
	//char IPdotdec[20] = {};
	//if (NULL == inet_ntop(AF_INET, (PVOID*)&sSvrAddr.sin_addr, IPdotdec, 20))
	//{
	//	printf("inet_ntop失败1,%d", ::GetLastError());
	//}
	int cycle = 1;
	while (1)
	{
		if (m_lastPort > m_alloc_max)
		{
			++cycle;
			if (cycle >= 2)
			{
				return false;
			}
			m_lastPort = m_alloc_min;
		}
		sSvrAddr.sin_port = htons(m_lastPort);
		SOCKET iSvrFd = socket(AF_INET, SOCK_DGRAM, 0);
		if (0 == ::bind(iSvrFd, (struct sockaddr*)&sSvrAddr, sizeof(sSvrAddr)))
		{
			//该端口可用
			port = m_lastPort;
			return true;

		}
#ifdef WIN32
		printf("错误码为:%d", ::GetLastError());
		closesocket(iSvrFd);
#else
		close(iSvrFd);
#endif 

		//端口不可用,重新分配
		m_lastPort.fetch_add(1);
	}
	return false;
}

bool CAlloct_port::SetAllocPortMin(const unsigned int& minport)
{
	if (minport < 0 || minport > 65535)
	{
		return false;
	}
	m_alloc_min = minport;
	m_lastPort = m_alloc_min;
	return true;
}
bool CAlloct_port::SetAllocPortMax(const unsigned int& maxport)
{
	if (maxport < 0 || maxport > 65535)
	{
		return false;
	}
	m_alloc_max = maxport;
	return true;
}
CAlloct_port::CAlloct_port()
		:m_alloc_min(1024),
		m_alloc_max(65535)
	{
		m_lastPort = m_alloc_min;
		m_Instance = nullptr;
#ifdef WIN32
		WSADATA wsa;
		WSAStartup(MAKEWORD(2, 2), &wsa);
#endif
	}
CAlloct_port::~CAlloct_port()
	{
#ifdef WIN32
		WSACleanup();
#endif
	}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值