获取空闲端口号
当我们使用端口时要获取空闲的端口,端口数量最大为65536个。
通过Bind函数获取
SOCKET s = socket(AF_INET,SOCK_STREAM,IPPROTO_IP);
sockaddr_in addr;
addr.sin_family = AF_INET;
addr.sin_port = htons(usPort);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(s,(LPSOCKADDR)&addr,sizeof(addr));
if(WSAGetLastError() == WSAEADDRINUSE)
{
//端口已被占用
usPort++;
}
else
{
//将端口释放掉
closesocket(s);
break;
}
不推荐使用,有些情获取不到。
通过TCP连接表和UDP连接表获取
判断当前端口是否空闲时,要同时判断TCP连接表和UDP连接表,使用函数GetTcpTable和 GetUdpTable获取两个表的信息,进行解析。
#include <tcpmib.h>
#include <IPHlpApi.h>
#include <WinSock2.h>
#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"Iphlpapi.lib")
//获取Tcp端口状态
BOOL TCPPort(ULONG nPort)
{
MIB_TCPTABLE* TcpTable = NULL;
DWORD nSize = 0;
//获取表的大小,分配内存
if (GetTcpTable(TcpTable, &nSize, TRUE) == ERROR_INSUFFICIENT_BUFFER)
{
TcpTable = (MIB_TCPTABLE*) malloc ((UINT) nSize);
}
if(NO_ERROR == GetTcpTable(TcpTable, &nSize, TRUE))
{
DWORD nCount = (*TcpTable).dwNumEntries;
if (nCount > 0)
{
for(DWORD i=0;i<nCount;i++)
{
MIB_TCPROW TcpRow = (*TcpTable).table[i];
DWORD temp1 = TcpRow.dwLocalPort;
int temp2 = temp1 / 256 + (temp1 % 256) * 256;
if(temp2 == nPort)
{
if (TcpTable != NULL)
{
delete TcpTable;
}
return TRUE;
}
}
}
if (TcpTable != NULL)
{
delete TcpTable;
}
return FALSE;
}
if (TcpTable != NULL)
{
delete TcpTable;
}
return FALSE;
}
//获取Udp端口状态
BOOL UDPPort (ULONG nPort)
{
MIB_UDPTABLE* UdpTable = NULL;
DWORD nSize = 0;
if (GetUdpTable(UdpTable, &nSize, TRUE) == ERROR_INSUFFICIENT_BUFFER)
{
UdpTable = (MIB_UDPTABLE*) malloc ((UINT) nSize);
}
if(NO_ERROR == GetUdpTable(UdpTable, &nSize,TRUE))
{
DWORD nCount = (*UdpTable).dwNumEntries;
if (nCount > 0)
{
for(DWORD i=0;i<nCount;i++)
{
MIB_UDPROW TcpRow = (*UdpTable).table[i];
DWORD temp1 = TcpRow.dwLocalPort;
int temp2 = temp1 / 256 + (temp1 % 256) * 256;
if(temp2 == nPort)
{
if (UdpTable != NULL)
{
delete UdpTable;
}
return TRUE;
}
}
}
if (UdpTable != NULL)
{
delete UdpTable;
}
return FALSE;
}
if (UdpTable != NULL)
{
delete UdpTable;
}
return FALSE;
}
int GetFreePort()
{
unsigned short usPort = 20000;
while(TRUE)
{
if (!TCPPort(usPort))
{
if (!UDPPort(usPort))
{
break;
}
}
usPort++;
}
return usPort;
}
判断是否在同一网段
判断是否在同一网段也就是判断能否 connect 成功,但是 connect 自己设定的超时时间太长不方便使用,通过设置非阻塞模式,使用 select 函数来判断是否 connect 成功,select 一般用来判断可读写性,但是 select 函数有个返回时间所以可以设定超时时间,所以当 select 返回时可以判断是否连接。
BOOL JudgeIPAndProtConnect(const string &strIp, int &iPort) //接受一个IP和端口
{
BOOL bJub = TRUE;
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
return FALSE;
}
do
{
//socket设置为非阻塞
unsigned long on = 1;
if (ioctlsocket(ConnectSocket, FIONBIO, &on) < 0)
{
bJub = FALSE;
break;
}
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_port = htons(iPort);
clientService.sin_addr.s_addr = inet_addr(strIp.c_str());
if (connect(ConnectSocket, (SOCKADDR*) &clientService, sizeof(clientService) ) == SOCKET_ERROR)
{
bJub = FALSE;
break;
}
//设置时间
fd_set writeset;
FD_ZERO(&writeset);
FD_SET(ConnectSocket, &writeset);
timeval tv;
tv.tv_sec = 2; //秒
tv.tv_usec = 0; //毫秒
int ret = select(ConnectSocket + 1, NULL, &writeset, NULL, &tv);
if (ret == 0)
{
bJub = FALSE;
} else if (ret < 0)
{
bJub = FALSE;
}
} while (FALSE);
closesocket(ConnectSocket);
return bJub;
}