📄 lancommuniondlg.cpp
字号:
// LANCommunionDlg.cpp : implementation file
//
/********************************************************
* 局域网文件传输 聊天工具 *
* Wi-Fi 2007年7月8日 *
* 文件传输端口 5200 *
* 聊天 端口 5208 *
********************************************************/
#include "stdafx.h"
#include "LANCommunion.h"
#include "LANCommunionDlg.h"
#include "MySocket.h"
#include <process.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
HANDLE g_hEvent=NULL; //用于控制只有一个接收文件线程在运行。
HANDLE g_hEventSend=NULL; //用于控制只有一个发送文件线程在运行。
DWORD g_dwSendCount=0; //已发送的字节数。
DWORD g_dwRecvCount=0; //已接收的字节数。
int g_nSendSecond=0;
int g_nRecvSecond=0;
CRITICAL_SECTION g_criticalSend;
CRITICAL_SECTION g_criticalRecv;
/////////////////////////////////////////////////////////////////////////////
// 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( );
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
if(SOCKET_ERROR==err)
{
AfxMessageBox(GetError(GetLastError( )));
sock.Close( );
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
err=sock.Receive(fileName,NAMELENGTH);//接收文件名
if(0==err)
{
AfxMessageBox("连接被关闭了。");
sock.Close( );
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
if(SOCKET_ERROR==err)
{
AfxMessageBox(GetError(GetLastError( )));
sock.Close( );
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
CFileArrive dlg;
dlg.m_fileName.Format("文件\r\n\t%s\r\n\t到达是否接收?",fileName);
if( IDCANCEL==dlg.DoModal( ) )
{
sock.Close( );
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
CFileDialog fdlg(false,NULL,fileName);//保存文件对话框。
modal=fdlg.DoModal( );
if(IDCANCEL==modal)
{
sock.Close( );
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0; //用户取消保存。
}
savePathName=fdlg.GetPathName( );
//////////////////////////////////////////////////////////////
int finish=0;
DWORD step=0;
CFile file;
char buffer[BUFFERSIZE];
CProgressCtrl* pProgress;
if( 0==file.Open(savePathName,CFile::modeWrite |CFile::modeCreate| CFile::typeBinary) )
{
AfxMessageBox("打开要写入的文件出错。");
sock.Close( );
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
pProgress=(CProgressCtrl*)sp.pCLAN->GetDlgItem(IDC_PROGRESS);
pProgress->ShowWindow(SW_SHOW);
pProgress->SetRange32(0,Length);
pProgress->SetPos( 0 );
EnterCriticalSection(&g_criticalRecv);
g_nRecvSecond=1;
LeaveCriticalSection(&g_criticalRecv);
sp.pCLAN->m_speed.ShowWindow(SW_SHOW);
sp.pCLAN->SetTimer(WM_TIMER_RECVCOUNT,1000,NULL);
while( true )
{
finish=sock.Receive(buffer,BUFFERSIZE);
if(0==finish)
break;
if(SOCKET_ERROR==finish)
{
AfxMessageBox(GetError(GetLastError( )));
sock.Close( );
sp.pCLAN->m_speed.ShowWindow(SW_HIDE);
sp.pCLAN->KillTimer(WM_TIMER_RECVCOUNT);
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
file.Write(buffer,finish);
step+=finish;
EnterCriticalSection(&g_criticalRecv);
g_dwRecvCount=step;
LeaveCriticalSection(&g_criticalRecv);
pProgress->SetPos( step );
pProgress->Invalidate(false);
}
file.Close( );
sock.Close( );
pProgress->SetPos( 0 );
pProgress->ShowWindow(SW_HIDE);
sp.pCLAN->m_speed.ShowWindow(SW_HIDE);
sp.pCLAN->KillTimer(WM_TIMER_RECVCOUNT);
//重置事件对象为有信号状态,准备下次接收 。
if(!SetEvent(g_hEvent))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
CString strFinish;
strFinish.Format("已成功接收文件\r\n\r\n%s",fileName);
AfxMessageBox(strFinish);
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;
}
//设置事件对象为有信号状态。
if(!SetEvent(g_hEvent))
{
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;
if(WAIT_FAILED==WaitForSingleObject(g_hEvent,INFINITE))
{
AfxMessageBox("等待事件对象失败。");
sockServer.Close( );
return 0;
}
AfxBeginThread(SaveFileSingle,(LPVOID)¶m);
//////////////////////////////////////////////////////////////////////////////
}
sockServer.Close( );
return 0;
}
//////////////// 单线程发送文件线程。 ///////////////////////////////////
UINT SendFileSingle( LPVOID param )
{
if (!AfxSocketInit())
{
AfxMessageBox("SendFileSingle AfxSocketInit( )失败。");
return 0;
}
//等待g_hEventSend为有信号状态时再开始发送文件。
if(WAIT_FAILED==WaitForSingleObject(g_hEventSend,INFINITE))
{
// AfxMessageBox("等待事件对象失败。");
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) )
{
AfxMessageBox("打开要发送的文件出错。");
//重置事件对象为有信号状态,准备下次发送 。
if(!SetEvent(g_hEventSend))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
Length=file.GetLength( );
//创建发送套接字准备发送。
CSocket sockSend;
if(0==sockSend.Create( ) )
{
AfxMessageBox("创建发送套接字出错。");
//重置事件对象为有信号状态,准备下次发送 。
if(!SetEvent(g_hEventSend))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
return 0;
}
if(0==sockSend.Connect( ip, FILEPORT ) )
{
AfxMessageBox("发送文件连接出错,可能是对方不在线。\r\n"+GetError(GetLastError( )));
//重置事件对象为有信号状态,准备下次发送 。
if(!SetEvent(g_hEventSend))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
sockSend.Close( );
return 0;
}
if(SOCKET_ERROR ==sockSend.Send(&Length,sizeof(DWORD)))//发送文件长度
{
AfxMessageBox("发送文件长度出错。\r\n"+GetError(GetLastError( )));
//重置事件对象为有信号状态,准备下次发送 。
if(!SetEvent(g_hEventSend))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
sockSend.Close( );
return 0;
}
if(SOCKET_ERROR ==sockSend.Send(fileName,NAMELENGTH))//发送文件名
{
AfxMessageBox("发送文件名出错。\r\n"+GetError(GetLastError( )));
//重置事件对象为有信号状态,准备下次发送 。
if(!SetEvent(g_hEventSend))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
sockSend.Close( );
return 0;
}
DWORD step=0;
int over,err;
((CWnd*)pCLAN->GetDlgItem(IDC_PROGRESS))->ShowWindow(SW_SHOW);
pCLAN->m_Progress.SetRange32(0,Length);
pCLAN->m_Progress.SetPos(0);
EnterCriticalSection(&g_criticalSend);
g_nSendSecond=1;
LeaveCriticalSection(&g_criticalSend);
pCLAN->m_speed.ShowWindow(SW_SHOW);
pCLAN->SetTimer(WM_TIMER_SENDCOUNT,1000,NULL);
//发送文件内容。
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( )));
//重置事件对象为有信号状态,准备下次发送 。
if(!SetEvent(g_hEventSend))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
sockSend.Close( );
pCLAN->GetDlgItem(IDC_PROGRESS)->ShowWindow(SW_HIDE);
pCLAN->KillTimer(WM_TIMER_SENDCOUNT);
pCLAN->m_speed.ShowWindow(SW_HIDE);
return 0;
}
step+=err;
EnterCriticalSection(&g_criticalSend);
g_dwSendCount=step;
LeaveCriticalSection(&g_criticalSend);
pCLAN->m_Progress.SetPos( step );
pCLAN->m_Progress.Invalidate(false);
}while( true );
file.Close( );
sockSend.Close( );
pCLAN->m_Progress.SetPos(0);
pCLAN->GetDlgItem(IDC_PROGRESS)->ShowWindow(SW_HIDE);
pCLAN->KillTimer(WM_TIMER_SENDCOUNT);
pCLAN->m_speed.ShowWindow(SW_HIDE);
//重置事件对象为有信号状态,准备下次发送 。
if(!SetEvent(g_hEventSend))
{
// AfxMessageBox("重置事件对象为有信号状态时出错。");
return 0;
}
CString strFinish;
strFinish.Format("已成功发送文件\r\n\r\n%s。",fileName);
AfxMessageBox(strFinish);
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])
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -