VC++实现NAT穿透之NAT类型检测

  // NatCheck.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"   
#include <process.h>  
#include <stdio.h>   
#include <afx.h>
#include "winsock2.h"
#include "./Include/packet.h"
#pragma comment(lib,"./lib/wininet.lib") 
#pragma comment(lib,"wsock32.lib") 
#include "ws2tcpip.h" 
#include "string.h" 

#define N_SuperNode 5
#define N_NatCheckRequestQueue 20
#define PORT_SERVER_NATCHECK 8888
#define PORT_SERVER_NATCHECK_1 8889
#define PORT_CLIENT_NATCHECK 7777
#define PORT_SERVER_CLIENT_INFO 4444
#define N_CheckTime 5 //最多检测次数

SOCKET sClient,sServer;//客户端和服务端的socket号
struct sockaddr_in sn1_addr,sn2_addr,sn_addr,client_addr;
struct sockaddr_in client_addr_deal;
struct in_addr in_addr_tmp,in_addr_tmp1;
FILE *fp; //客户端读取hostcache.txt文件指针
int i=0,j=0;
unsigned long int snIP[N_SuperNode];//读取的SN的IP地址列表
unsigned short int snPort[N_SuperNode];//读取的SN的Port列表
char tmpIP[15],tmpPort[5];
char ch;
char IP_return[15];
/* 本client的网络类型:
* 0 = public net
* 1 = full cone nat
* 2 = symmetric nat
* 3 = restricted cone nat
* 4 = port restricted cone nat
*/
unsigned long int myID=0,friendID=26;//本client和friend的用户ID
char myNetType=-1,friendNetType=-1;
unsigned long int myPubIp,friendPubIp,myPriIp,friendPriIp;
unsigned short int myPubPort,friendPubPort,myPriPort,friendPriPort;
//natCheck请求包结构
struct natCheckPacket{
 char version;
 char dowhat;
 unsigned short int port;
 unsigned long int ip;
 unsigned long int id;
}natCheckPacket;
typedef struct natCheckPacket NCP;
char buff[sizeof(natCheckPacket)];//发包用的缓冲区
//natCheck请求数据结构
struct natCheckRequest{
 NCP ncp;//缓存到来的请求包
 struct natCheckRequest * next;//指向下一个请求数据
 unsigned long int ip;//发送请求的client IP地址
 unsigned short int port;//发送请求的client Port
}natCheckRequest;
typedef struct natCheckRequest NCR;
struct netInfoResponsePacket{
 NCP ncp;
 unsigned long int ip_pub;
 unsigned short int port_pub;
 unsigned short int no;
}netInfoResponsePacket;
typedef struct netInfoResponsePacket NIRP;
//natCheck请求数据循环队列
NCR natCheckRequestQueue[N_NatCheckRequestQueue];
NCR * h_NatCheckRequestQueue,* t_NatCheckRequestQueue;
/*
 * 获得本地主机IP地址
 */
char * getownIP()
{
 //  
 //   获得主机名.   
 char   hostname[256];  
 int   res   =   gethostname(hostname,   sizeof(hostname));  
 if   (res   !=   0)   {  
  printf("Error:   %u/n",   WSAGetLastError());  
  return "failed";  
 }    
   
 //   根据主机名获取主机信息.  
 hostent*   pHostent   =   gethostbyname(hostname);  
 if   (pHostent==NULL)   {  
  printf("Error:   %u/n",   WSAGetLastError());  
  return   "failed";  
 }  
 //  
 //   解析返回的hostent信息.   
 hostent&   he   =   *pHostent;  
 sockaddr_in   sa;  
    memcpy   (   &sa.sin_addr.s_addr,   he.h_addr_list[0],he.h_length);  
 return inet_ntoa(sa.sin_addr);  
}
unsigned long int getownIP_uli()
{
 //  
 //   获得主机名.   
 char   hostname[256];  
 int   res   =   gethostname(hostname,   sizeof(hostname));  
 if   (res   !=   0)   {  
  printf("Error:   %u/n",   WSAGetLastError());  
  return -1;  
 }    
   
 //   根据主机名获取主机信息.  
 hostent*   pHostent   =   gethostbyname(hostname);  
 if   (pHostent==NULL)   {  
  printf("Error:   %u/n",   WSAGetLastError());  
  return   -1;  
 }  
 //  
 //   解析返回的hostent信息.   
 hostent&   he   =   *pHostent;  
 sockaddr_in   sa;  
    memcpy   (   &sa.sin_addr.s_addr,   he.h_addr_list[0],he.h_length);  
 return sa.sin_addr.S_un.S_addr;
}
/*
 * superNode接收请求线程入口函数
 */
unsigned int _stdcall ThreadFunction_sn_get(void *param)
{
 //创建套接字
 if( (sServer = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)
 {
  printf("获取SOCKET号失败!!!/n");
  return 0;
 }
 //绑定套接字和本机地址和端口  
 sn_addr.sin_family=AF_INET;
 sn_addr.sin_port=htons(PORT_SERVER_NATCHECK);
 sn_addr.sin_addr.s_addr =INADDR_ANY ;//inet_addr(getownIP());  //
 if(bind(sServer, (struct sockaddr*)&sn_addr, sizeof(sn_addr)) < 0 )
 {
  printf("不能将服务器地址捆绑到SOCKET号上!!!/n");
  closesocket(sServer);
  return 0;
 }
 //printf("接收..../n");
 int iLen=sizeof(client_addr);
 struct natCheckPacket * ncp=(struct natCheckPacket *)buff;
 int timeout=300; 
 while (1)
 {
  setsockopt(sServer, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout,sizeof(timeout));
  if(recvfrom(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr,&iLen)!=-1)
  {
   //判断队列是否满
   if(t_NatCheckRequestQueue->next!=h_NatCheckRequestQueue)
   {
    //先修改t
    NCR * t=t_NatCheckRequestQueue;
    t_NatCheckRequestQueue=t->next;
    //再写入
    t->ncp=*(ncp);
    t->ip=client_addr.sin_addr.S_un.S_addr;
    t->port=client_addr.sin_port;
   }
  }
  Sleep(300);
  //printf("version:%d/tdowhat:%d/tport:%d/tip:%d/n",ncp->version,ncp->dowhat,
  // ncp->port,ncp->ip);
  //printf("Client said: %s/n",buff);
  //strcpy(buff,"I am a server!!/n");
  //sendto(sServer,buff,sizeof(buff),0,(sockaddr*)&client_addr,sizeof(client_addr));
 } 
 //closesocket(sServer);
 return 0;
}
/*
 * 构造NCP包发送给SuperNode
 * 接受返回的NCP包
*/
int sendNCPtoSNandRecvNCP(unsigned long int ip_SN,unsigned short int port_SN,
    NCP ncp_send)
{
 int timeout=300; 
 sn_addr.sin_addr.S_un.S_addr=ip_SN;
 sn_addr.sin_family=AF_INET;
 sn_addr.sin_port=htons(port_SN); 
 int iLen=sizeof(sn_addr);
 NCP * ncp=(NCP *)buff;
 ncp->version=ncp_send.version;
 ncp->dowhat=ncp_send.dowhat;
 ncp->port=ncp_send.port;
 ncp->ip=ncp_send.ip; 
 ncp->id=ncp_send.id;
 setsockopt(sClient, SOL_SOCKET , SO_SNDTIMEO, (char *)&timeout,sizeof(timeout));
 sendto(sClient,buff,sizeof(buff),0,(SOCKADDR*)&sn_addr,iLen);
 in_addr_tmp.S_un.S_addr=ip_SN;
 in_addr_tmp1

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

尹成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值