www.pudn.com > UDP文件传输.rar > p2psvr.cpp
// p2psvr.cpp : Defines the entry point for the console application.
//
//#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
//#define UNI_CURRENT_SYSTEM MS_WINDOWS
#include "HMutex.h"
#include "HList.h"
#include "HUdpSock.h"
#include "HTime.h"
#include "HFile.h"
#include "ZsProxySvr.h"
#include "ZsP2pUserList.h"
//#define MU_THREAD
#define _TEST 1
CHTime sys_time;
struct P2P_SvrTask{
UNI_DWORD dwTickCount;
P2P_SVRITEM user;
UDPFILE_CMD cmd;
UNI_DWORD dwIP;
UNI_WORD wPort;
};
typedef CHList P2P_TaskList;
#define MAX_USER_COUNT ((UNI_DWORD)-1)
UNI_WORD m_port;
CHUdpSock m_sock;
CZsP2pUserList m_UserList;
static UNI_DWORD m_MaxUserCount=MAX_USER_COUNT;
P2P_TaskList m_tasks;
P2P_TaskList::NODETYPE *FindTask(P2P_SVRITEM *pUser,UNI_DWORD dwFileID,char *sendName,char *recvName)
{
P2P_TaskList::NODETYPE *pNode;
P2P_TaskList::HLISTPOSTION pos;
if(pos=m_tasks.MoveToBegin())
{
while(pNode=m_tasks.MoveToNext(pos))
{
if(strcmp(pNode->user.userName,pUser->userName)==0 &&
pNode->cmd.head.trans_id==dwFileID &&
strcmp(pNode->cmd.head.user_name,sendName)==0 &&
strcmp(pNode->cmd.head.append_str,recvName)==0)
{
return pNode;
}
}
}
return UNI_NULL;
}
void OnTestSvr(UDPFILE_CMD *pcmd)
{
#ifdef _TEST
HFile file;
char buf[128];
// if(file.OpenForAppend("c:\\p2p_svr_test.txt"))
{
sprintf(buf,"%d\r\n",pcmd->head.trans_id);
// file.Write(buf,sprintf(buf,"%d\r\n",pcmd->head.trans_id));
// file.Close();
printf(buf);
}
#endif
}
void OnClientQuit(UDPFILE_CMD *pcmd)
{
P2P_SVRITEM user;
P2P_TaskList::NODETYPE *pTask;
P2P_TaskList::HLISTPOSTION pos;
printf("received %s's QUIT_CMD [outip=%s outport=%d] [inip=%d inport=%d]\r\n",pcmd->head.user_name,HSocket::getipstr(pcmd->head.out_ip),pcmd->head.out_port,
pcmd->head.use_ip,pcmd->head.use_port);
if(m_UserList.GetUserInfo(pcmd->head.user_name,&user))
{
if(pos=m_tasks.MoveToBegin())
{
while(pTask=m_tasks.MoveToNext(pos))
{
if(strcmp(pTask->user.userName,user.userName)==0)
{
m_tasks.Remove(pTask);
}
}
}
m_UserList.RemovUser(pcmd->head.user_name);
}
}
void OnClientHere(UDPFILE_CMD *pcmd)
{
/*
收到客户发来的报告位置的信息,建立客户信息
*/
P2P_SVRITEM user,user2;
UDPFILE_CMD cmd;
printf("received %s's HERE_CMD [outip=%s outport=%d] [inip=%d inport=%d]\r\n",
pcmd->head.user_name,HSocket::getipstr(pcmd->head.out_ip),pcmd->head.out_port,
pcmd->head.use_ip,pcmd->head.use_port);
user.dwTickCount=UNI_GetTickCount();
user.outIp=pcmd->head.out_ip;
user.outPort=pcmd->head.out_port;
user.useIp=pcmd->head.use_ip;
user.usePort=pcmd->head.use_port;
strncpy(user.userName,pcmd->head.user_name,sizeof(user.userName));
if(m_UserList.GetUserInfo(pcmd->head.user_name,&user2)==UNI_FALSE)
{
if(m_UserList.GetUserCount()head.out_ip,pcmd->head.out_port);
printf("\t\treturn it!\r\n");
}
void OnClientFileReq(UDPFILE_CMD *pcmd)
{
/*
收到发送方对接收方地址的请求
若查得接收方回答UDP_SVR_FILE_ACK,同时若是第一次对该任务的请求用UDP_SVR_FILE_REQ通知接收方
若十秒内未查到回答UDP_SVR_FILE_WAIT,超过十秒回答UDP_SVR_FILE_NO
*/
P2P_SVRITEM user,user2;
UDPFILE_CMD cmd;
UNI_DWORD dwTickCount;
P2P_TaskList::NODETYPE *pTask;
printf("received %s's REQ_CMD [outip=%s outport=%d] [inip=%d inport=%d]\r\n",pcmd->head.user_name,HSocket::getipstr(pcmd->head.out_ip),pcmd->head.out_port,
pcmd->head.use_ip,pcmd->head.use_port);
if((pcmd->head.other_len>1 ) &&
(pcmd->fileName[pcmd->head.other_len-1]==0) )//&&
{
if(m_UserList.GetUserInfo(pcmd->head.user_name,&user))//找到发送方
{
dwTickCount=UNI_GetTickCount();
user.outIp=pcmd->head.out_ip;
user.outPort=pcmd->head.out_port;
user.useIp =pcmd->head.use_ip;
user.usePort=pcmd->head.use_port;
user.dwTickCount=dwTickCount;
memcpy(&cmd,pcmd,sizeof(cmd.head));
cmd.head.other_len=pcmd->head.other_len>sizeof(cmd.fileName)?sizeof(cmd.fileName):pcmd->head.other_len;
strncpy(cmd.fileName,pcmd->fileName,cmd.head.other_len);
cmd.head.type=UDP_FILE_CMD;
cmd.head.user_data_len=0;
if(m_UserList.GetUserInfo(pcmd->head.append_str,&user2))//找到接收方
{
printf("find recver: %s\n",user2.userName);
//创建或利用一个UDP_SVR_FILE_REQ任务
pTask=FindTask(&user2,pcmd->head.trans_id,pcmd->head.user_name,pcmd->head.append_str);
if(pTask==UNI_NULL)
{
pTask=m_tasks.AddTail();
pTask->dwTickCount=0;
}
if(pTask)
{
//为接收方准备命令
memcpy(&pTask->user,&user2,sizeof(user2));
memcpy(&pTask->cmd,&cmd,sizeof(pTask->cmd));
//传递用户的出IP和端口
*((UNI_DWORD*)&pTask->cmd.fileName[cmd.head.other_len])=user2.outIp;
*((UNI_WORD*)&pTask->cmd.fileName[cmd.head.other_len+sizeof(user2.outIp)])=user2.outPort;
pTask->cmd.head.user_data_len =(sizeof(user2.outIp)+sizeof(user2.outPort));
pTask->cmd.head.cmd=UDP_SVR_FILE_REQ;
pTask->cmd.head.type=UDP_FILE_CMD;
//通道号不能优化
pTask->cmd.head.out_ip=user.outIp;
pTask->cmd.head.out_port=user.outPort;//发送方通道号
cmd.head.out_ip=user2.outIp;
cmd.head.out_port=user2.outPort;//接收方通道号
////////为双方通信优化
if(pcmd->head.out_ip==user2.outIp)
{
cmd.head.use_ip=user2.useIp;
cmd.head.use_port=user2.usePort;
pTask->cmd.head.use_ip=user.useIp;
pTask->cmd.head.use_port=user.usePort;
}
else
{
cmd.head.use_ip=user2.outIp;
cmd.head.use_port=user2.outPort;
pTask->cmd.head.use_ip=user.outIp;
pTask->cmd.head.use_port=user.outPort;
}
/////////////先回答发送方再通知接收方
cmd.head.cmd=UDP_SVR_FILE_ACK;
*((UNI_DWORD *)&cmd.fileName[cmd.head.other_len])=user.outIp;
*((UNI_WORD *)&cmd.fileName[cmd.head.other_len+sizeof(UNI_DWORD)])=user.outPort;
cmd.head.user_data_len=sizeof(UNI_DWORD)+sizeof(UNI_WORD);
m_sock.SendTo(&cmd,sizeof(cmd.head)+cmd.head.other_len+cmd.head.user_data_len,user.outIp,user.outPort);
printf("\t\tsend SVR_FILE_ACK to %s\r\n",user.userName);
////////////下面通知接收方///////////////////
if(pTask->dwTickCount==0)//第一次收到该任务
{
m_sock.SendTo(&pTask->cmd,sizeof(pTask->cmd),user2.outIp,user2.outPort);
printf("\t\tsend SVR_FILE_REQ to %s\r\n",user2.userName);
}
pTask->dwTickCount=dwTickCount;
}
m_UserList.SetUser(&user);
}
else//未找到接收方
{
cmd.head.cmd=UDP_SVR_FILE_WAIT;
if(pcmd->head.other_info!=0)
{
if(dwTickCount < pcmd->head.other_info ||
(dwTickCount-pcmd->head.other_info)>10000)
cmd.head.cmd=UDP_SVR_FILE_NO;
cmd.head.other_info=pcmd->head.other_info;
}
else
cmd.head.other_info =dwTickCount;
cmd.head.use_ip=cmd.head.out_ip=user.outIp;
cmd.head.use_port=cmd.head.out_port=user.outPort;//应答此处给出被应答客户的通道号
m_sock.SendTo(&cmd,sizeof(cmd),user.outIp,user.outPort);
}
}
}
}
void OnClientAck(UDPFILE_CMD *pcmd)
{
/*
收到客户的ACK只能是由UDP_SVR_FILE_REQ引起的
*/
P2P_SVRITEM user;
P2P_TaskList::NODETYPE *pTask;
printf("received %s's ACK_CMD [outip=%s outport=%d] [inip=%d inport=%d]\r\n",pcmd->head.user_name,HSocket::getipstr(pcmd->head.out_ip),pcmd->head.out_port,
pcmd->head.use_ip,pcmd->head.use_port);
// if(true)
{
if(m_UserList.GetUserInfo(pcmd->head.user_name,&user))//找到的是接收方的信息
{
user.outIp=pcmd->head.out_ip;
user.outPort=pcmd->head.out_port;
user.useIp =pcmd->head.use_ip;
user.usePort=pcmd->head.use_port;
user.dwTickCount=UNI_GetTickCount();
if(pTask=FindTask(&user,pcmd->head.trans_id,pcmd->head.append_str,pcmd->head.user_name))
{
printf("\t\tremove the task:sender=%s recver=%s filename=%s\r\n",pTask->cmd.head.user_name,pTask->cmd.head.append_str,pTask->cmd.fileName);
m_tasks.Remove(pTask);
}
m_UserList.SetUser(&user);
}
}
}
static UDP_SVRBUF m_cmd_buf;
#ifdef MU_THREAD
class MyProxy:public CZsProxySvr
#else
class MyProxy:public IZsProxySvr
#endif
{
static void GetAddr(char *username,UNI_DWORD &ip,UNI_WORD &port)
{
P2P_SVRITEM user;
ip=0;
port=0;
if(m_UserList.GetUserInfo(username,&user))//找到的是接收方的信息
{
ip=user.outIp;
port=user.outPort;
}
}
virtual void SendTo(UDPFILE_CMD *pcmd)
{
UNI_DWORD ip;
UNI_WORD port;
GetAddr(pcmd->head.append_str,ip,port);
if(ip!=0 && port!=0)
{
pcmd->head.type=UDP_FILE_PROXY;
m_sock.SendTo(pcmd,pcmd->head.other_len+pcmd->head.user_data_len+sizeof(pcmd->head),ip,port);
#ifdef _DEBUG
printf("PROXY:%s send pack to %s\n",pcmd->head.user_name,pcmd->head.append_str );
#endif
}
}
}m_proxy;
int main(int argc, char* argv[])
{
P2P_TaskList::NODETYPE *pTask;
P2P_TaskList::HLISTPOSTION pos;
UNI_DWORD dwTickCount;
HSocket::Initialize();
(argc==2)?m_port=atoi(argv[1]):m_port=4096;
if(UNI_FALSE==m_proxy.StartWork())
{
sys_time.GetCurTime();
printf("p2p svr can not start proxy\r\n");
return 0;
}
if(m_sock.CreateAt(m_port))
{
printf("%d year %d month %d day p2p svr start at port:%d\r\n",sys_time.GetYear(),sys_time.GetMonth(),sys_time.GetDay(),m_port);
}
else
{
printf("p2p svr start failed at port:%d\r\n",m_port);
return 0;
}
while(1)
{
if(m_sock.WaitForRead(0,10000))
{
if(dwTickCount=m_sock.RecvFrom(&m_cmd_buf.cmd,sizeof(m_cmd_buf),m_cmd_buf.cmd.head.out_ip,m_cmd_buf.cmd.head.out_port))
{
if(m_cmd_buf.cmd.head.other_len +m_cmd_buf.cmd.head.user_data_len+sizeof(m_cmd_buf.cmd.head)<=dwTickCount &&
m_cmd_buf.cmd.head.type==UDP_FILE_CMD &&
dwTickCount>=sizeof(m_cmd_buf.cmd.head) )
{
switch(m_cmd_buf.cmd.head.cmd)
{
case UDP_CLIENT_HERE:
OnClientHere(&m_cmd_buf.cmd);
break;
case UDP_CLIENT_ACK:
OnClientAck(&m_cmd_buf.cmd);
break;
case UDP_CLIENT_FILE_REQ:
OnClientFileReq(&m_cmd_buf.cmd);
break;
case UDP_CLIENT_QUIT:
OnClientQuit(&m_cmd_buf.cmd);
break;
//////////////以下是代理命令/////////////////////////////////////////
case UDP_FILE_DATA:
case UDP_FILE_SEND_CANCEL:
case UDP_FILE_END:
case UDP_FILE_SUCCESS_ACK:
case UDP_FILE_NEXT:
case UDP_FILE_RECV_CANCEL:
case UDP_FILE_SUCCESS:
case UDP_READY_TEST:
case UDP_READY_OK:
m_proxy.AddToCmdList(&m_cmd_buf);
break;
default:
printf("recv from:(%s,%d) cmd=%d\r\n",HSocket::getipstr(m_cmd_buf.cmd.head.out_ip),
m_cmd_buf.cmd.head.out_port,
m_cmd_buf.cmd.head.cmd,m_cmd_buf.cmd.head.other_len,
m_cmd_buf.cmd.head.user_data_len,
m_cmd_buf.cmd.head.type);
}
}
else if((m_cmd_buf.cmd.head.cmd==(UNI_WORD)UDP_COMMAND_TEST) && m_cmd_buf.cmd.head.type == (UNI_WORD)UDP_FILE_TEST)
{
OnTestSvr(&m_cmd_buf.cmd);
}
}
else
printf("bad recv from:(%s,%d) cmd=%d objlen=%d,userlen=%d type=%d\r\n",
HSocket::getipstr(m_cmd_buf.cmd.head.out_ip),
m_cmd_buf.cmd.head.out_port,
m_cmd_buf.cmd.head.cmd,m_cmd_buf.cmd.head.other_len,m_cmd_buf.cmd.head.user_data_len);
}
else
{
dwTickCount=UNI_GetTickCount();
//////////////////////////删除过期而没有任务的用户
m_UserList.DeleteUsers(30000,dwTickCount);
}
//////////////扫描任务,超时者删除,否则重发
dwTickCount=UNI_GetTickCount();
if(pos=m_tasks.MoveToBegin())
{
while(pTask=m_tasks.MoveToNext(pos))
{
if(dwTickCountdwTickCount || (dwTickCount-pTask->dwTickCount)>10000)
{
printf("time out delete stask sender=%s recver=%s filename=%s\r\n",pTask->cmd.head.user_name,pTask->cmd.head.append_str,
pTask->cmd.fileName);
m_tasks.Remove(pTask);
}
else if((UNI_DWORD)(dwTickCount-pTask->dwTickCount)>1000 )
{
m_sock.SendTo(&pTask->cmd,sizeof(pTask->cmd),pTask->user.outIp,pTask->user.outPort);
printf("resend %s's $s REQ to %s\r\n",pTask->cmd.head.user_name,pTask->cmd.fileName,pTask->cmd.head.append_str);
}
}
}
}
return 0;
}