⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 lancommuniondlg.cpp

📁 计算机是网络的一个课程设计。文件传输&聊天 里面是WORD类型(包含源代码)
💻 CPP
📖 第 1 页 / 共 3 页
字号:
// 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)&param);
		//////////////////////////////////////////////////////////////////////////////
	}
	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 + -