#pragma comment(lib,"ws2_32.lib")
#include "windows.h"
#include "proto.h"
#include "Exception.h"
#include <iostream>
using namespace std;
UserList ClientList;
unsigned int Localip; //定义自己的IP地址
#define COMMANDMAXC 256
#define MAXRETRY 5
SOCKET PrimaryUDP;
char LocalUserName[10];
char ServerIP[20];
char host_address[256];
bool RecvedACK;
void InitWinSock()
{
WSADATA wsaData;
HOSTENT *host_entry;
char host_name[256];
if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
{
printf("Windows sockets 2.2 startup");
throw Exception("");
}
else{
printf("Using %s (Status: %s)\n",
wsaData.szDescription, wsaData.szSystemStatus);
printf("with API versions %d.%d to %d.%d\n\n",
LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion),
LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
gethostname(host_name,256); //获取本机名字
host_entry=gethostbyname(host_name);
if(host_entry!=0)
{
wsprintf(host_address,"%d.%d.%d.%d",(host_entry->h_addr_list[0][0]&0x00ff),(host_entry->h_addr_list[0][1]&0x00ff),
(host_entry->h_addr_list[0][2]&0x00ff),(host_entry->h_addr_list[0][3]&0x00ff));
}
}
SOCKET mksock(int type)
{
SOCKET sock = socket(AF_INET, type, 0);
if (sock < 0)
{
printf("create socket error");
throw Exception("");
}
return sock;
}
stUserListNode GetUser(char *username)
{
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), username) == 0 )
return *(*UserIterator);
}
throw Exception("not find this user");
}
//绑定socket对象的函数,填入ip,端口后,将socket对象与socket地址对象绑定。
void BindSock(SOCKET sock)
{
sockaddr_in sin;
sin.sin_addr.S_un.S_addr = INADDR_ANY;
sin.sin_family = AF_INET;
sin.sin_port = htons(CLIENT_PORT);
if (bind(sock, (struct sockaddr*)&sin, sizeof(sin)) < 0)
throw Exception("bind error");
}
//总目的:写上自己的用户名,服务器的ip地址后,登陆服务器
bool ConnectToServer(SOCKET sock,char *username, char *serverip)
{
sockaddr_in remote;//用来保存服务器的地址信息
remote.sin_addr.S_un.S_addr = inet_addr(serverip);
remote.sin_family = AF_INET;
remote.sin_port = htons(SERVER_PORT);
stMessage sendbuf; //用来发送LOGIN消息,告诉服务器新用户登陆
sendbuf.iMessageType = LOGIN;
strncpy(sendbuf.message.loginmember.userName, username, 10); //消息里面保存了用户名,在这里填上自己写的用户名
sendto(sock, (const char*)&sendbuf, sizeof(sendbuf), 0, (const sockaddr*)&remote,sizeof(remote));//发送LOGIN消息到服务端
int usercount;
unsigned short loggingtag;
int fromlen = sizeof(remote);
int iread = recvfrom(sock, (char *)&loggingtag, sizeof(unsigned short), 0, (sockaddr *)&remote, &fromlen);//接受loggingtag消息,这个标记为0时表示名字被占用,为1标记未被占用
if(iread<=0)
{
throw Exception("Login error\n");
}
if(!loggingtag)
{
printf("Sorry, your nickname has been used.\n");
return false; //标记为0时以false退出
}
iread = recvfrom(sock, (char *)&usercount, sizeof(int), 0, (sockaddr *)&remote, &fromlen);//服务端接受发来的用户数量。
//总目的:登录到服务端后,接收服务端发来的已经登录的用户的信息
cout<<"Have "<<usercount<<" users logined server:"<<endl;
for(int i = 0;i<usercount;i++)
{
stUserListNode *node = new stUserListNode;
recvfrom(sock, (char*)node, sizeof(stUserListNode), 0, (sockaddr *)&remote, &fromlen);
ClientList.push_back(node);
cout<<"Username:"<<node->userName<<endl;
if(strcmp(node->userName,username)==0) //看到自己的用户名时,记录自己的外网IP
{
Localip=node->ip;
}
in_addr tmp;
tmp.S_un.S_addr = htonl(node->ip);
cout<<"UserIP:"<<inet_ntoa(tmp)<<endl;
cout<<"UserPort:"<<node->port<<endl;
cout<<""<<endl;
}
return true;
}
void OutputUsage()
{
cout<<"You can input you command:\n"
<<"Command Type:\"send\",\"exit\",\"getu\"\n"
<<"Example : send Username Message\n"
<<" exit\n"
<<" getu\n"
<<endl;
}
//发送一个消息给某个用户C,直接向C的外网IP发送消息,如果此前没有联系过,那么此消息将无法发送,发送端等待超时。超时后,发送端将发送一个请求信息到服务端,要求服务端发送给C一个请求,请求C给本机发送打洞消息,以上将重复MAXRETRY次
bool SendMessageTo(char *UserName, char *Message)
{
char realmessage[512]; //保存要发送的内容
unsigned int UserIP;
unsigned short UserPort;
bool FindUser = false;
sockaddr_in server; //定义服务器信息
server.sin_addr.S_un.S_addr = inet_addr(ServerIP);
server.sin_family = AF_INET;
server.sin_port = htons(SERVER_PORT);
//通过输入的Username在Clientlist中寻找对应的用户信息
for(UserList::iterator UserIterator=ClientList.begin();
UserIterator!=ClientList.end();
++UserIterator)
{
if( strcmp( ((*UserIterator)->userName), UserName) == 0 ) //找到对应名称的用户
{
UserIP = (*UserIterator)->ip;
UserPort = (*UserIterator)->port;
if(UserIP==Localip) //当发现对方跟自己的外网ip一样的时候,就证明对方跟自己是同一个局域网
{
stMessage getlocalipmessage;
getlocalipmessage.iMessageType=GETLOCALUSER; //发现对方的外网IP跟自己一样,那么就发送消息给服务器通知对方发送对方内网IP
strncpy(getlocalipmessage.message.logoutmember.userName, UserName, 10);
sendto(PrimaryUDP, (const char*)&getlocalipmessage, sizeof(getlocalipmessage), 0, (const sockaddr*)&server, sizeof(server));
while((*UserIterator)->Localornot==0) //当localornot=0,说明还未接受到对方的内网信息,继续等待
{
Sleep(100); //等待对方的内网IP的到来,到来后localornot被改成1
}
UserPort = (*UserIterator)->port; //设置成对方的内网端口
UserIP = (*UserIterator)->ip; //设置成对方的内网ip
}
FindUser = true;
}
}
if(!FindUser)
return false;
memset(realmessage,0,256);
memcpy(realmessage,LocalUserName,strlen(LocalUserName));
strcat(realmessage," says: ");
strcat(realmessage, Message);
for(int i=0;i<MAXRETRY;i++)
{
RecvedACK = false; //当RecvedACK为false的时候,表示从来没跟指定用户联系过。True则代表联系过了。
sockaddr_in remote; //定义socket地址对象,保存对方的地址
remote.sin_addr.S_un.S_addr = htonl(UserIP);
remote.sin_family = AF_INET;
remote.sin_port = htons(UserPort);
stP2PMessage MessageHead; //定义P2P消息对象,这里类型为P2PMESSAGE。这个P2P消息对象只包括发送内容的长度
MessageHead.iMessageType = P2PMESSAGE;
MessageHead.iStringLen = (int)strlen(realmessage)+1;
int isend = sendto(PrimaryUDP, (const char *)&MessageHead, sizeof(MessageHead), 0, (const sockaddr*)&remote, sizeof(remote)); //发送P2P消息给指定用户,让对方知道是P2P消息,并且知道内容的长度
isend = sendto(PrimaryUDP, (const char *)&realmessage, MessageHead.iStringLen, 0, (const sockaddr*)&remote, sizeof(remote)); //发送realmessage给指定用户,对方已经知道该消息有多长
//等待RecvedACK状态的修改,当线程接受到指定用户的消息后,就会改它。这时候表示已经跟指定用户联系过了。
for(int j=0;j<10;j++)
{
if(RecvedACK)
return true; //一旦是True了,说明联系过了,那么以上realmessage是发送成功了,所以结束返回这个函数了。
else
Sleep(300); //一旦是false了,说明并没联系过,那么以上realmessage是发送失败了,所以要发送打洞命令给指定用户。
}
//总目的:发送请求信息给服务器,要服务器告诉指定用户打个洞过来
stMessage transMessage;
transMessage.iMessageType = P2PTRANS; //这个消息类型定义为打洞命令
strcpy(transMessage.message.translatemessage.userName, UserName);//填写指定用户的用户名,好让服务器知道让哪个用户打洞
没有合适的资源?快使用搜索试试~ 我知道了~
p2p.rar_nat p2p udp
共30个文件
h:4个
pdb:4个
opt:2个
1.该资源内容由用户上传,如若侵权请联系客服进行举报
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
2.虚拟产品一经售出概不退款(资源遇到问题,请及时私信上传者)
版权申诉
0 下载量 106 浏览量
2022-09-14
18:54:09
上传
评论
收藏 3.17MB RAR 举报
温馨提示
利用UDP协议穿透NAT代理的P2P设计与应用
资源推荐
资源详情
资源评论
收起资源包目录
p2p.rar (30个子文件)
20110331
client
P2PClient.dsp 3KB
P2PClient.ncb 33KB
proto.h 2KB
P2PClient.cpp 16KB
P2PClient.dsw 541B
Exception.h 392B
Debug
P2PClient.ilk 792KB
vc60.idb 193KB
P2PClient.pdb 1.06MB
vc60.pdb 140KB
P2PClient.obj 237KB
P2PClient.pch 5.44MB
P2PClient.exe 520KB
P2PClient.opt 48KB
P2PClient.plg 759B
server
P2PServer.dsw 541B
P2PServer.dsp 3KB
P2PServer.cpp 9KB
proto.h 2KB
P2PServer.ncb 33KB
P2PServer.opt 48KB
Exception.h 392B
P2PServer.plg 759B
Debug
P2PServer.obj 51KB
vc60.idb 177KB
P2PServer.pch 4.38MB
P2PServer.exe 168KB
P2PServer.ilk 199KB
vc60.pdb 100KB
P2PServer.pdb 361KB
共 30 条
- 1
资源评论
御道御小黑
- 粉丝: 58
- 资源: 1万+
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功