- VC在局域网中通过http协议获取公网IP地址
- 最后还是用http协议请求解决了,使用wireshark截取了这个请求的内容,然后通过套接字发送给服务器,于是得到想要的ip地址:
- #pragma comment(lib, "ws2_32.lib")
- #include<iostream>
- #include<WinSock2.h>
- using namespace std;
- void main()
- {
- char peer[] = "GET / HTTP/1.1\r\n\
- User-Agent:My_Agenter\r\n\
- Host:ip.dnsexit.com\r\n\r\n";
- WSADATA A;
- WSAStartup(MAKEWORD(2,2),&A);
- SOCKET a=socket(2,1,0);
- hostent *p=gethostbyname("ip.dnsexit.com");//获取主机地址
- sockaddr_in addr;
- addr.sin_addr=*(in_addr*)p->h_addr_list[0];//使用地址列表的第一个进行连接,实际上也只有这一个
- //addr.sin_addr.S_un.S_addr=::inet_addr("67.214.175.69 \r\n");//这个是可以的,想说明函数inet_addr(char *ip)可以接受ip字符串末尾有空格和换行符而不受影响
- addr.sin_family=2;
- addr.sin_port=htons(80);//http的80端口
- connect(a,(sockaddr*)&addr,sizeof(sockaddr_in));
- send(a,peer,sizeof(peer),0);//发送http的GET请求
- char text[600]={0};
- recv(a,text,sizeof(text),0);//接受服务器返回的值
- int i=0;
- while(text[i]!='\n'||text[i+1]!='\r')//去掉前面的信息
- i++;
- char ip[20];
- strcpy(ip,&text[i+3]);//得到ip地址开始位置,复制到字符串ip中
- puts(ip);
- closesocket(a);
- WSACleanup();
- }
原文:http://blog.csdn.net/jokers_i/article/details/6715627
- 最后还是用http协议请求解决了,使用wireshark截取了这个请求的内容,然后通过套接字发送给服务器,于是得到想要的ip地址:
- #pragma comment(lib, "ws2_32.lib")
- #include<iostream>
- #include<WinSock2.h>
- using namespace std;
- void main()
- {
- char peer[] = "GET / HTTP/1.1\r\n\
- User-Agent:My_Agenter\r\n\
- Host:ip.dnsexit.com\r\n\r\n";
- WSADATA A;
- WSAStartup(MAKEWORD(2,2),&A);
- SOCKET a=socket(2,1,0);
- hostent *p=gethostbyname("ip.dnsexit.com");//获取主机地址
- sockaddr_in addr;
- addr.sin_addr=*(in_addr*)p->h_addr_list[0];//使用地址列表的第一个进行连接,实际上也只有这一个
- //addr.sin_addr.S_un.S_addr=::inet_addr("67.214.175.69 \r\n");//这个是可以的,想说明函数inet_addr(char *ip)可以接受ip字符串末尾有空格和换行符而不受影响
- addr.sin_family=2;
- addr.sin_port=htons(80);//http的80端口
- connect(a,(sockaddr*)&addr,sizeof(sockaddr_in));
- send(a,peer,sizeof(peer),0);//发送http的GET请求
- char text[600]={0};
- recv(a,text,sizeof(text),0);//接受服务器返回的值
- int i=0;
- while(text[i]!='\n'||text[i+1]!='\r')//去掉前面的信息
- i++;
- char ip[20];
- strcpy(ip,&text[i+3]);//得到ip地址开始位置,复制到字符串ip中
- puts(ip);
- closesocket(a);
- WSACleanup();
- }
多个服务器节点的测速代码
RT,经常会有情况,在客户端需要测试到多个服务器节点的速度情况,原理其实很简单,就是向各个节点发一个简单的请求,然后判断应答回来的时间,差值就是响应时间了。
其中有许多可以优化的地方:
1)并发请求,同时向多个服务器发送请求,这样可以将整个测速的时间缩短到串行测速的几分之一
A)建立n个非阻塞的socket连接到n个服务器
B)将这n个socket加入到fdWrite,select判断是否可写 C)某socket可写时,即代表连接成功,此时发送请求,并从写套接字集合中清除掉,并加入读套接字集合 D)某socket可读时,代表应答回来,此时计算响应时间,并从读套接字集合中清除掉,并关掉套接字2)只根据需求测试需要用到的服务器数量,有足够可用服务器后,不再测试其他服务器。因为我们的网络状况,除非双线接入的网络,否则对于电信和联通的服务器必然会有一两个响应非常慢,这种测试是无意义的
A)在上述select循环时检测已经测速完成的服务器数,如果数量已经足够则退出循环
B)初始化时为所有服务器节点的响应时间赋一个极大值,表示测速失败
3)保证测速函数互斥访问,同一时间调用多次是毫无意义的,而且会干扰结果
A)使用一个静态变量表示是否正在测速过程中,如果在则直接返回(不要使用临界区,多次连续的测速也毫无意义 )
实现代码如下 ,将自己需要的请求赋给strRequest即可
//测试Web服务器的响应
void TestWebServer()
{
static bool bInPorcess = false;// 不要重复测速
if (bInPorcess)
return;
bInPorcess = true;
// 构造HEAD方法请求头
CStringA strReqest;
LockServerAddrArray();
std::vector<ServInfo> serverArray = m_serverArray;
UnLockServerAddrArray();
static int nTestCount = 0;//统计测试累计次数
++nTestCount;
mainLog()->write_log(em_utility::ll_normal, "第%d次测试速度。。。", nTestCount);
char buf[1500];
typedef std::map<ULONG, ServInfo> ServMap;
ServMap servMap;
for (ServerInfoList::iterator iter = serverArray.begin(); iter != serverArray.end(); ++iter)
{
SOCKET sock = socket(AF_INET, SOCK_STREAM, 0);
ULONG ul;
ul = 1;
ioctlsocket(sock, FIONBIO, &ul); //设置为非阻塞模式
SOCKADDR_IN saServer;
saServer.sin_family = AF_INET;
saServer.sin_port = htons(80);
saServer.sin_addr.s_addr = inet_addr(iter->strIP);
connect(sock, (struct sockaddr *)&saServer, sizeof(saServer));
servMap[sock] = *iter;
iter->nResponeTime = 0xEFFF;
}
mainLog()->write_log_2("begin waiting...");
DWORD dwStartTime = GetTickCount();
fd_set fdSocket;
FD_ZERO(&fdSocket);
for (ServMap::iterator iter = servMap.begin(); iter != servMap.end(); ++iter)
{
FD_SET(iter->first, &fdSocket);
}
timeval tv = {6, 0};
fd_set fdWriteTotal = fdSocket;
fd_set fdReadTotal;
FD_ZERO(&fdReadTotal);
int nTestedCount = 0;
while (nTestedCount < 5)// 多余的服务器不再测速,无意义
{
fd_set fdRead = fdReadTotal;
fd_set fdWrite = fdWriteTotal;
if (fdReadTotal.fd_count == 0 && fdWriteTotal.fd_count == 0)
break;
int nRet = select(0, &fdRead, &fdWrite, NULL, &tv);
ATLTRACE("select : %d -- %d\n", nRet, GetTickCount() - dwStartTime);
if (nRet > 0)
{
for (int nIndex = 0; nIndex < (int)fdSocket.fd_count; ++nIndex)
{
SOCKET sock = fdSocket.fd_array[nIndex];
if (FD_ISSET(sock, &fdWrite))// 可写,发送请求
{
send(sock, strReqest, strReqest.GetLength(), 0);
FD_CLR(sock, &fdWriteTotal);// 清除掉
FD_SET(sock, &fdReadTotal);
ATLTRACE("socket: %d, send! \n", sock);
}
if (FD_ISSET(sock, &fdRead))
{
nRet = recv(sock, buf, sizeof(buf), 0); // 从webserver获取数据
servMap[sock].nResponeTime = (GetTickCount() - dwStartTime);
for (std::vector<ServInfo>::iterator iter = serverArray.begin(); iter != serverArray.end(); ++iter)// 效率比较低的实现,暂时方案
{
if (iter->strIP == servMap[sock].strIP)
{
iter->nResponeTime = servMap[sock].nResponeTime;
}
}
ATLTRACE("socket: %d, read! \n", sock);
closesocket(sock);
FD_CLR(sock, &fdReadTotal);// 不再侦听这个套接字
servMap.erase(sock);
++nTestedCount;
}
}
}
else if (nRet <= 0)// select 超时,退出
{
mainLog()->write_log(em_utility::ll_error, "select ret: %d, error: %d", nRet, WSAGetLastError());
break;
}
}
for (ServMap::iterator iter = servMap.begin(); iter != servMap.end(); ++iter)
{
closesocket(iter->first);
}
sort(serverArray.begin(), serverArray.end());
for (std::vector<ServInfo>::iterator iter = serverArray.begin(); iter != serverArray.end(); ++iter)
{
mainLog()->write_log(em_utility::ll_normal, "iter->strServ = %s, iter->strIP = %s, iter->nResponseTime = %d", iter->strServ, iter->strIP, iter->nResponeTime);
}
LockServerAddrArray();
m_serverArray = serverArray;
UnLockServerAddrArray();
bInPorcess = false;
}