📄 lancommuniondlg.cpp
字号:
// LANCommunionDlg.cpp : implementation file
//
/********************************************************
* 局域网文件传输 聊天工具加强版 *
* 合肥工业大学 *
* 计算机科学与技术 计算机04-5班 *
* Wi-Fi 2007年7月8日 *
* 加强版完成日期 2007年9月25日 *
* 文件传输端口 5200 *
* 聊天 端口 5208 *
********************************************************/
#include "stdafx.h"
#include "LANCommunion.h"
#include "LANCommunionDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
struct SAVEFILEPARAM
{
SOCKET sock;
CLANCommunionDlg* pCLAN;
};
typedef SAVEFILEPARAM BROADCAST;
struct SENDFILEPARAM
{
CString pathName;
CString ip;
char fileName[NAMELENGTH];
CLANCommunionDlg* pCLAN;
};
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////
CString GetError( DWORD err )
{
CString strError;
switch(err)
{
case WSANOTINITIALISED:
strError="初始化错误";
break;
case WSAENOTCONN:
strError="对方没有启动";
break;
case WSAEWOULDBLOCK :
strError="对方已经关闭";
break;
case WSAECONNREFUSED:
strError="连接的尝试被拒绝";
break;
case WSAENOTSOCK:
strError="在一个非套接字上尝试了一个操作";
break;
case WSAEADDRINUSE:
strError="特定的地址已在使用中";
break;
case WSAECONNRESET:
strError="与主机的连接被关闭";
break;
default:
strError="一般错误";
}
return strError;
}
/////////////////////////////////////////////////////////////////////////////
///////////// 聊天线程 //////////////////////////////////////////////////
UINT ChatReceive( LPVOID param )
{
CHAT* pChat=(CHAT*)param;
//客户端地址簇。
SOCKADDR_IN addrDest;
int len=sizeof(SOCKADDR),err;
char cchat[1024];
while( true )
{
CString schatOld;
memset(cchat,0,1024);
schatOld.Empty( );
//接收数据。
err=recvfrom(pChat->sock,cchat,1024,0,(SOCKADDR*)&addrDest,&len);
if(SOCKET_ERROR==err)
{
// AfxMessageBox("接收聊天消息出错。"+GetError(GetLastError()));
continue;
}
//更新聊天内容。
CWnd* pMain=AfxGetApp( )->m_pMainWnd;
pMain->GetDlgItemText(IDC_EDIT_RECEIVE,schatOld);
schatOld+="\r\n";
schatOld+=cchat;
pMain->SetDlgItemText(IDC_EDIT_RECEIVE,schatOld);
pMain->GetDlgItem(IDC_EDIT_RECEIVE)->
SendMessage(WM_VSCROLL,SB_BOTTOM);
Sleep(55);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////
//////////////// 单线程接收文件线程 ////////////////
UINT SaveFileSingle( LPVOID param )
{
SAVEFILEPARAM sp;
sp.pCLAN=((SAVEFILEPARAM*)param)->pCLAN;
sp.sock=((SAVEFILEPARAM*)param)->sock;
CSocket sock;
sock.Attach( sp.sock );
DWORD Length;
char fileName[NAMELENGTH];
CString savePathName;
int modal,err;
memset(fileName,0,NAMELENGTH);
err=sock.Receive(&Length,sizeof(DWORD));//接收文件长度
if(0==err)
{
AfxMessageBox("连接被关闭了。");
sock.Close( );
return 0;
}
if(SOCKET_ERROR==err)
{
AfxMessageBox(GetError(GetLastError( )));
sock.Close( );
return 0;
}
err=sock.Receive(fileName,NAMELENGTH);//接收文件名
if(0==err)
{
AfxMessageBox("连接被关闭了。");
sock.Close( );
return 0;
}
if(SOCKET_ERROR==err)
{
AfxMessageBox(GetError(GetLastError( )));
sock.Close( );
return 0;
}
CFileArrive dlg;
dlg.m_fileName.Format("文件\r\n\t%s\r\n\t到达是否接收?",fileName);
if( IDCANCEL==dlg.DoModal( ) )
{
sock.Close( );
return 0;
}
CFileDialog fdlg(false,NULL,fileName);//保存文件对话框。
modal=fdlg.DoModal( );
if(IDCANCEL==modal)
{
sock.Close( );
return 0; //用户取消保存。
}
savePathName=fdlg.GetPathName( );
//////////////////////////////////////////////////////////////
int finish=0;
DWORD step=0;
CFile file;
char buffer[BUFFERSIZE];
if( 0==file.Open(savePathName,CFile::modeWrite |CFile::modeCreate| CFile::typeBinary) )
{
AfxMessageBox("打开要写入的文件出错。");
sock.Close( );
return 0;
}
CTransportInfoDlg* pDialog=new CTransportInfoDlg();
sp.pCLAN->SendMessage(UM_CREATE_TRANSPORTDLG,(WPARAM)pDialog);
pDialog->m_progress.SetRange32(0,Length);
pDialog->m_progress.SetPos(0);
DWORD timeStart,timeEnd,time,speed;
CString s;
timeStart=::GetTickCount( );
s.Format(_T("正在接收文件: %s"),fileName);
pDialog->m_title.SetWindowText(s);
while( true )
{
finish=sock.Receive(buffer,BUFFERSIZE);
if(0==finish)
break;
if(SOCKET_ERROR==finish)
{
AfxMessageBox(GetError(GetLastError( )));
sock.Close( );
sp.pCLAN->SendMessage(UM_DELETE_DLG,(WPARAM)pDialog);
sp.pCLAN->SetFocus( );
return 0;
}
if(pDialog->m_bEnd)
{
sock.Close( );
sp.pCLAN->SendMessage(UM_DELETE_DLG,(WPARAM)pDialog);
sp.pCLAN->SetFocus( );
return 0;
}
file.Write(buffer,finish);
step+=finish;
///////////////////////////////////////////////////////
//更新对传输信息对话框消息。
pDialog->m_progress.SetPos(step);
timeEnd=::GetTickCount( );
time=timeEnd-timeStart;
time/=1000;
if(time>0)
{
speed=((step/time)>>10);
if(1024>speed) //Speed is k/BPS
{
s.Format("接收速度为:%dK/BPS",speed);
pDialog->m_speed.SetWindowText(s);
}
else //Speed is M/BPS
{
s.Format("接收速度为:%dM/BPS",speed>>10);
pDialog->m_speed.SetWindowText(s);
}
}
///////////////////////////////////////////////////////
}
file.Close( );
sock.Close( );
sp.pCLAN->SendMessage(UM_DELETE_DLG,(WPARAM)pDialog);
CString strFinish;
strFinish.Format("已成功接收文件\r\n\r\n%s",fileName);
AfxMessageBox(strFinish);
sp.pCLAN->SetFocus( );
return 0;
}
/////////////////////////////////////////////////////////////////////
//////////////// 单线程监听有无文件传输连接。 /////////////////
UINT ListenFileTransport( LPVOID param)
{
CLANCommunionDlg* pCLAN=(CLANCommunionDlg*)param;
CSocket sockServer;
if (!AfxSocketInit())
{
AfxMessageBox("ListenFileTransport AfxSocketInit( )失败。");
return 0;
}
if( 0==sockServer.Create( FILEPORT ) )
{
AfxMessageBox("监听套接字创建失败。");
return 0;
}
if( 0==sockServer.Listen( ) )
{
AfxMessageBox("监听套接字监听失败。");
sockServer.Close( );
return 0;
}
//监听套接字创建成功。
//发送文件按钮可用。
pCLAN->m_SendFile.EnableWindow(true);
//监听套接字等待连接请求。
while( true )
{
CSocket sockClient;
if( 0==sockServer.Accept( sockClient ) )
{
AfxMessageBox("监听套接字接受服务失败。");
sockServer.Close( );
break ;
}
//用线程函数来接收文件。
/////////////////////////////////////////////////////////////////////////////
SAVEFILEPARAM param;
param.sock=sockClient.Detach( );
param.pCLAN=pCLAN;
AfxBeginThread(SaveFileSingle,(LPVOID)¶m);
//////////////////////////////////////////////////////////////////////////////
}
sockServer.Close( );
return 0;
}
//////////////// 单线程发送文件线程。 ///////////////////////////////////
UINT SendFileSingle( LPVOID param )
{
if (!AfxSocketInit())
{
AfxMessageBox("SendFileSingle AfxSocketInit( )失败。");
return 0;
}
CLANCommunionDlg* pCLAN=((SENDFILEPARAM*)param)->pCLAN;
CString ip;
char fileName[NAMELENGTH];
char buffer[BUFFERSIZE];
DWORD Length;
CFile file;
memset(fileName,0,NAMELENGTH);
strcpy(fileName,((SENDFILEPARAM*)param)->fileName);
ip=((SENDFILEPARAM*)param)->ip;
if( 0==file.Open(((SENDFILEPARAM*)param)->pathName,CFile::modeRead | CFile::typeBinary) )
{
return 0;
}
Length=file.GetLength( );
//创建发送套接字准备发送。
CSocket sockSend;
if(0==sockSend.Create( ) )
{
AfxMessageBox("创建发送套接字出错。");
return 0;
}
if(0==sockSend.Connect( ip, FILEPORT ) )
{
AfxMessageBox("发送文件连接出错,可能是对方不在线。\r\n"+GetError(GetLastError( )));
sockSend.Close( );
return 0;
}
if(SOCKET_ERROR ==sockSend.Send(&Length,sizeof(DWORD)))//发送文件长度
{
AfxMessageBox("发送文件长度出错。\r\n"+GetError(GetLastError( )));
sockSend.Close( );
return 0;
}
if(SOCKET_ERROR ==sockSend.Send(fileName,NAMELENGTH))//发送文件名
{
AfxMessageBox("发送文件名出错。\r\n"+GetError(GetLastError( )));
sockSend.Close( );
return 0;
}
DWORD step=0;
int over,err;
CTransportInfoDlg* pDialog=new CTransportInfoDlg();
pCLAN->SendMessage(UM_CREATE_TRANSPORTDLG,(WPARAM)pDialog);
pDialog->m_progress.SetRange32(0,Length);
pDialog->m_progress.SetPos(0);
DWORD timeStart,timeEnd,time,speed;
CString s;
timeStart=::GetTickCount( );
s.Format(_T("正在发送文件: %s"),fileName);
pDialog->m_title.SetWindowText(s);
//发送文件内容。
do
{
file.Seek(step,CFile::begin);
over=file.Read(buffer,BUFFERSIZE);
err=sockSend.Send(buffer,over);
if( BUFFERSIZE>over )
break;
if(SOCKET_ERROR==err)
{
AfxMessageBox("发送文件内容出错。\r\n"+GetError(GetLastError( )));
sockSend.Close( );
pCLAN->SendMessage(UM_DELETE_DLG,(WPARAM)pDialog);
pCLAN->SetFocus( );
return 0;
}
if(pDialog->m_bEnd)
{
sockSend.Close( );
pCLAN->SendMessage(UM_DELETE_DLG,(WPARAM)pDialog);
pCLAN->SetFocus( );
return 0;
}
step+=err;
///////////////////////////////////////////////////////
//更新对传输信息对话框消息。
pDialog->m_progress.SetPos(step);
timeEnd=::GetTickCount( );
time=timeEnd-timeStart;
time/=1000;
if(time>0)
{
speed=((step/time)>>10);
if(1024>speed) //Speed is k/BPS
{
s.Format("发送速度为:%dK/BPS",speed);
pDialog->m_speed.SetWindowText(s);
}
else //Speed is M/BPS
{
s.Format("发送速度为:%dM/BPS",speed>>10);
pDialog->m_speed.SetWindowText(s);
}
}
///////////////////////////////////////////////////////
}while( true );
file.Close( );
sockSend.Close( );
pCLAN->SendMessage(UM_DELETE_DLG,(WPARAM)pDialog);
CString strFinish;
strFinish.Format("已成功发送文件\r\n\r\n%s。",fileName);
AfxMessageBox(strFinish);
pCLAN->SetFocus( );
delete (SENDFILEPARAM*)param;
return 0;
}
/////////////////////////////////////////////////////////////////////////////
////////////////////// 接收广播消息线程 ////////////////////////
UINT ReceiveBroadcast( LPVOID param )
{
SOCKET sock=((BROADCAST*)param)->sock;
CLANCommunionDlg* pCLAN=((BROADCAST*)param)->pCLAN;
int err,nListItemCount,nListItemDelete;
bool del,bItemExist;
char buf[210];
char bufHost[200];
CString ip,strFind;
sockaddr_in addrFrom;
int len=sizeof(sockaddr);
// CListCtrl* pList=(CListCtrl*)pCLAN->GetDlgItem(IDC_LIST_USER);
while( true )
{
del=false;
memset(bufHost,0,200);
memset(buf,0,210);
ip.Empty( );
err=recvfrom(sock,buf,210,0,(sockaddr*)&addrFrom,&len);
if(SOCKET_ERROR==err)
{
// AfxMessageBox("接收广播数据出错。");
continue;
}
ip=inet_ntoa(addrFrom.sin_addr);
//检查是否为请求返回是否在线的确认消息。
if(buf[0]=='\t'&&buf[1]=='\t'&&buf[2]=='\t'&&buf[3]=='\t')
{
int iIndex=4;
int n=0;
int result;
while(0!=buf[iIndex])
bufHost[n++]=buf[iIndex++];
//获取主机名
char pMyhost[200];
memset(pMyhost,0,200);
if( 0==gethostname(pMyhost,200) );
else strcpy(pMyhost,"Anony");
sockaddr_in addrTo;
addrTo.sin_addr.S_un.S_addr=addrFrom.sin_addr.S_un.S_addr;
addrTo.sin_family=AF_INET;
addrTo.sin_port=htons(RECVPORT);
result=sendto(sock,pMyhost,strlen(pMyhost)+1,0,(sockaddr*)&addrTo,sizeof(sockaddr));
if(SOCKET_ERROR==result)
{
AfxMessageBox("发送返回在线确认消息出错。");
continue;
}
result=sendto(sock,pMyhost,strlen(pMyhost)+1,0,(sockaddr*)&addrTo,sizeof(sockaddr));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -