📄 p2p.cpp
字号:
// P2P.cpp: implementation of the CP2P class.
//
//////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////
// 功能: 文件传输类/ 客户端之间
// 日期: 2005-12-10
// 最后更新: 2005-12-18
//////////////////////////////////////////////////////////////////////
#include "stdafx.h"
#include "NetQQ.h"
#include "P2P.h"
#include "ChatDlg.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CP2P::CP2P()
{
m_bFileLinstenStatus = false;
m_Port = 0;
m_ftParam = NULL;
m_hdlFT = NULL;
}
CP2P::~CP2P()
{
closesocket(m_FileListenSocket);
WSACleanup();
}
/////////////////////////////////////////////////////////////////////////////
//初始化文件传输套接字并开始监听
void CP2P::InitFlieListenSock()
{
WORD wVersionRequested;
WSADATA wsaData;
int err;
wVersionRequested = MAKEWORD(1, 1);
err = WSAStartup(wVersionRequested, &wsaData);
if ( err != 0 )
{
return;
}
if ( LOBYTE( wsaData.wVersion ) != 1 ||
HIBYTE( wsaData.wVersion ) != 1 )
{
WSACleanup();
return;
}
//////////////////////////////////////////////////////////////
//创建文件传输socket
m_FileListenSocket = socket(AF_INET, SOCK_STREAM,IPPROTO_IP);
SOCKADDR_IN addr;
addr.sin_family = AF_INET;
addr.sin_addr.S_un.S_addr = htonl(INADDR_ANY);
addr.sin_port = htons(0);
int nSize = sizeof(addr);
///////////////////////////////////////////////////////////////////////
// 绑定套接字到本地IP和随即端口
if (SOCKET_ERROR == bind(m_FileListenSocket, (sockaddr*)&addr, nSize))
{
int i = WSAGetLastError();
AfxMessageBox("绑定本地文件传输套接字到端口失败!");
WSACleanup();
return;
}
// 监听所绑定的套接字端口
if (SOCKET_ERROR == listen(m_FileListenSocket, 5))
{
int i = WSAGetLastError();
AfxMessageBox("监听本地文件传输套接字失败!");
WSACleanup();
return;
}
// 获取由系统所分配的端口号
int nret = getsockname(m_FileListenSocket, (SOCKADDR*)&addr, &nSize);
if(nret)
{
CString tmp;
tmp.Format("获取由系统所分配的端口号 出错!错误号:%d。",nret);
AfxMessageBox(tmp);
WSACleanup();
return;
}
// 将网络续转换并放到成员变量中
m_Port = ntohs(addr.sin_port);
m_bFileLinstenStatus = true;
}
/////////////////////////////////////////////////////////////////////////////
//开启接收文件线程
void CP2P::OnAccept(CWnd* pWnd)
{
// 获取客户端以及连接用套接字
SOCKADDR_IN client;
int sClientLength = sizeof(client);
SOCKET s = accept(m_FileListenSocket, (sockaddr*)&client, &sClientLength);
// 定义接收和分解文件发送端发送的文件信息数据变量
CString strFileInfo,strRecv;
char buf[10240]="\0";
int nGet = 0;
do
{
nGet = recv(s, buf, sizeof(buf), MSG_PARTIAL);
}
while(nGet<1);//接收到不为空的
CString strArray[4];
CMsgBag mbTool;
tagPacketParam pp;
//判断接收到的是否跟打包的数据长度相等
int tmpn = mbTool.GetPacketLen(CString(buf)) + 4;
if (nGet != tmpn)
{
closesocket(s);
AfxMessageBox("接收到的文件信息缓存为空!");
return;
}
// 相等再拆包
mbTool.SplitDate(CString(buf), strArray);
DWORD exitCode = 0;
GetExitCodeThread(m_hdlFT,&exitCode);
if(exitCode == STILL_ACTIVE)
{
send(s, "NO", 2, MSG_PARTIAL);
closesocket(s);
return;
}
// 生成显示给用户的文件信息
//CString msg = "是否接收文件:"+ strArray[0]+"\n"+strArray[1]+"\n"+strArray[2]+"\n"+strArray[3];
CMainDlg* pMianWnd = (CMainDlg*)pWnd;
CChatDlg* pChatDlg = (CChatDlg*)pMianWnd->CreateChatWindow(strArray[0]);
CString strInfo = "文件传输请求,请单击右边的[是]或[否]接受或拒绝请求\r\n文件名:"
+ strArray[1] + " 大小:" + strArray[2];
pChatDlg->ShowFileTransferInfo(strInfo);
// 设置文件接收线程参数
m_ftParam = new _ThreadParam;
m_ftParam->m_pWnd = pChatDlg;
m_ftParam->m_sSock = s;
m_ftParam->m_strFileName = buf;
m_hdlFT = CreateThread(NULL, 0, AcceptFunc, (LPVOID)m_ftParam, 0, NULL);
}
/////////////////////////////////////////////////////////////////////////////
//文件接收处理线程
DWORD WINAPI CP2P::AcceptFunc(LPVOID lpParam)
{
// 接收参数
_ThreadParam* lp = (_ThreadParam*)lpParam;
CChatDlg* pDlg = (CChatDlg*)(lp->m_pWnd);
SOCKET s = lp->m_sSock;
CString strBuf = lp->m_strFileName;
//等待用户接受或拒绝文件传输回应
WaitForSingleObject(pDlg->GetMutex(), 30000);
//获取用户回应
UINT ret = pDlg->GetFileTransferChoose();
//拒绝接受
if(ret != faqYes)
{
if(ret == faqInit)
{
send(s, "OUT", 3, MSG_PARTIAL);
ReleaseMutex(pDlg->GetMutex());
pDlg->SetMutexNull();
CString msg = "等待超时,系统取消了文件传输回复请求...";
pDlg->ShowFileTransferInfo(msg);
pDlg->GetDlgItem(IDC_BTN_FYES)->ShowWindow(false);
pDlg->GetDlgItem(IDC_BTN_FNO)->ShowWindow(false);
}
pDlg->InitFileAcceptQuery();
closesocket(s);
delete lp; lp = NULL;
return 0;
}
pDlg->InitFileAcceptQuery();
pDlg->GetDlgItem(IDC_BTN_CANCLE)->ShowWindow(true);
////////////////////////////////////////////////////////////////////////
//获取接收文件信息
CString strArray[4];
CMsgBag mbTool;
mbTool.SplitDate(strBuf, strArray);
// 选择存放地址
CFileDialog fdlg(FALSE, NULL, strArray[1],
OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT, "所有文件(*.*)|*.*||");
if(fdlg.DoModal() == IDCANCEL)
{
closesocket(s);
pDlg->GetDlgItem(IDC_BTN_CANCLE)->ShowWindow(false);
delete lp; lp = NULL;
return 0;
}
// 返回接收回复
send(s, "T", 1, MSG_PARTIAL);
///////////////////////////////////////////////////////////////////////
//开始接收文件
CFile file;
CFileException e;
if(!file.Open(fdlg.GetPathName(), CFile::modeReadWrite|CFile::modeCreate
|CFile::shareDenyWrite, &e))
{
char err[128];
closesocket(s);
e.GetErrorMessage(err, 128);
pDlg->InsertNewChatInfo("文件打开失败:" + CString(err));
pDlg->GetDlgItem(IDC_BTN_CANCLE)->ShowWindow(false);
delete lp; lp = NULL;
return 3;
}
lp->m_pFile = &file;
pDlg->GetDlgItem(IDC_STCT0)->SetWindowText(file.GetFileName());
pDlg->GetDlgItem(IDC_STCT1)->SetWindowText("大小:" + strArray[2]);
CProgressCtrl* fprog = (CProgressCtrl*)pDlg->GetDlgItem(IDC_PRGR);
fprog->SetRange(0, 1000);
fprog->SetStep(1);
fprog->SetPos(0);
fprog->ShowWindow(true);
char buf[10240]="\0";
BOOL bRead = TRUE;
int nRecieve = 0;
char strSized[10] = "", strPecent[10] = "";
while(bRead)
{
int nResult = recv(s, buf, sizeof(buf), MSG_PARTIAL);
switch(nResult)
{
case 0:
{
bRead = FALSE;
break;
}
case SOCKET_ERROR:
{
if (GetLastError() != WSAEWOULDBLOCK)
{
bRead = FALSE;
}
break;
}
default:
file.Write(buf, nResult);
nRecieve += nResult;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -