通过编码来判断实际网络端口是否可用

在网络编程过程中,可能需要随机的去分配网络的业务端口来满足具体的网络通信业务(RTP收发流),那么需要程序代码随机的去分配可用的端口,为了满足该种业务需求,实现如下基础的业务代码:


头文件描述基础的业务接口

#ifndef NETPORTMGR_HPP_
#define NETPORTMGR_HPP_

#define _WIN32_WINNT 0x0501 

#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/pool/detail/singleton.hpp>

namespace ts
{

/**
 *@breif 端口管理封装
 *	
 */
class CNetPortMgr
{
public:
	CNetPortMgr();
	~CNetPortMgr();

public:
	void setUp( unsigned short port = 5000 );  // 设点起始端口
	void tearDown();

    bool generatePort( unsigned short& port, bool bUseUDP = true );
	void releasePort( unsigned short port );
	bool isUseablePort( unsigned short port, bool bUseUDP = true);

private:
	bool m_bSetUp;               // 标志位
	unsigned short m_basePort;   // 起始端口
	unsigned short m_nextPort;   // 下一个测试端口

private:
    boost::mutex m_portMutex; //支持多线程并发操作
    std::list<unsigned short> m_recyclePorts;   // 回收端口集合
};

typedef boost::details::pool::singleton_default<CNetPortMgr> NetPortMgrSingleton;  // 单件模式
}

#endif//NETPORTMGR_H


具体的实现过程如下

#include <iostream>
#include "NetPortMgr.hpp"

namespace ts
{

CNetPortMgr::CNetPortMgr()
: m_basePort( 0 )
, m_nextPort( 0 )
, m_bSetUp( false )
{
}

CNetPortMgr::~CNetPortMgr()
{
	m_recyclePorts.clear();
}

void CNetPortMgr::setUp( unsigned short port )
{
    boost::mutex::scoped_lock lock( m_portMutex );

    if ( m_bSetUp )
        return;

    m_basePort = ( port % 2 ) ? ( port + 1 ) : port;
    m_nextPort = m_basePort;
    m_recyclePorts.clear();
    m_bSetUp = true;
}

void CNetPortMgr::tearDown()
{
	boost::mutex::scoped_lock lock( m_portMutex );

	m_recyclePorts.clear();
	m_bSetUp = false;
}

bool CNetPortMgr::generatePort( unsigned short& port, bool bUseUDP )
{
	if ( !m_bSetUp )
	{
		setUp();
	}

	boost::mutex::scoped_lock lock( m_portMutex );

	///** 从已回收的端口中分配 */
	while ( !m_recyclePorts.empty() )
	{
		unsigned short tmpPort = m_recyclePorts.front();
		m_recyclePorts.pop_front();

		if ( isUseablePort( tmpPort, bUseUDP ) && isUseablePort( tmpPort + 1, bUseUDP ) )
		{
            printf("NetPortMgr::generatePort from recycle port: %d................... \n", tmpPort);
			port = tmpPort;
			return true;
		}
        else
        {
            printf("NetPortMgr::generatePort from recycle error!!!!!!port: %d................... \n", tmpPort);
        }
	}

	/** 找一个新的端口 */
	while ( 1 )
	{
		const unsigned OVER_FLOW_MAX = 65535; // uint16_t
		if ( ( (unsigned)m_nextPort + 2 ) > OVER_FLOW_MAX )
		{
			m_nextPort = m_basePort;
		}

		if ( !isUseablePort( m_nextPort ) || !isUseablePort( m_nextPort + 1 ) )
		{
			m_nextPort += 2;
			continue;
		}
		else
		{
			port = m_nextPort;
			m_nextPort += 2;
			break;
		}   
	}

	return true;	
}

void CNetPortMgr::releasePort( unsigned short port )
{
	boost::mutex::scoped_lock lock( m_portMutex );

	if ( !m_bSetUp )
		return;

	if ( std::find( m_recyclePorts.begin(), m_recyclePorts.end(), port ) != m_recyclePorts.end() )
		return;

	m_recyclePorts.push_back( port );	
}

/**
 *@breif 核心功能函数,通过网络方法确定端口是否被占用
 *	
 */
bool CNetPortMgr::isUseablePort( unsigned short port, bool bUseUDP)
{
#if defined( WIN32 ) && defined( _MSC_VER )
	SOCKET sock = INVALID_SOCKET;
#elif defined( __GNUC__ )
	int32_t sock = -1;
#endif

    if(bUseUDP == true)
    {
        sock = ::socket( AF_INET, SOCK_DGRAM, 0 );
    }
    else
    {
        sock = ::socket( AF_INET, SOCK_STREAM, 0 );
    }

#if defined( WIN32 ) && defined( _MSC_VER )
	if ( sock == INVALID_SOCKET )
#elif defined( __GNUC__ )
	if ( sock == -1 )
#endif
	{
		/** SOCKET错误 */
		return false;
	}

	struct sockaddr_in addr;
	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = INADDR_ANY;
	addr.sin_port = htons( port );

	/** 通过bind测试 */
#if defined( WIN32 ) && defined( _MSC_VER )
	if ( ::bind( sock, (struct sockaddr*)&addr, sizeof(addr) ) == SOCKET_ERROR )
	{
		::closesocket( sock );
		return false;
	}
	else
	{
		::closesocket( sock );
	}
#elif defined( __GNUC__ )
	if ( ::bind( sock, (struct sockaddr*)&addr, sizeof(addr) ) < 0 )
	{
		::close( sock );
		return false;
	}
	else
	{
		::close( sock );
	}
#endif
	boost::thread::sleep( boost::get_system_time() + boost::posix_time::millisec( 10 ) );

	return true;
}
}

如上代码可以直接使用,如有转载请支持版权

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值