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

📄 prichatdlg.cpp

📁 利用Visual C++的Windows SOCKET网络编程实现局域网内正在使用本程序的所有主机的群聊、两主机之间的点对点聊天和文件传送功能
💻 CPP
字号:
// PriChatDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Chat.h"
#include "PriChatDlg.h"
#include "ChatDlg.h"
#include "FileInfo.h"
#include <afxsock.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CPriChatDlg dialog

UINT FileRecvProc(LPVOID lParam);

//私聊对话框构造函数
CPriChatDlg::CPriChatDlg(CString m_host_IP,CString m_host_name,CWnd* pParent /*=NULL*/)
	: CDialog(CPriChatDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CPriChatDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	this->m_host_IP=m_host_IP;		//保存与此私聊对话框对应的用户主机名
	this->m_host_name=m_host_name;	//保存与此私聊对话框对应的用户IP	
	this->m_ptrDlg=(CChatDlg*)pParent;	//保存主对话框的指针
}


void CPriChatDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CPriChatDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}


BEGIN_MESSAGE_MAP(CPriChatDlg, CDialog)
	//{{AFX_MSG_MAP(CPriChatDlg)
	ON_BN_CLICKED(IDC_BTN_SEND, OnSend)
	ON_BN_CLICKED(IDC_BTN_FILE_SEND, OnBtnFileSend)
	ON_BN_CLICKED(IDC_BTN_FILE_RECV, OnBtnFileRecv)
	ON_BN_CLICKED(IDC_BTN_FILE_REFUSE, OnBtnFileRefuse)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CPriChatDlg message handlers

//发送私聊信息函数(私聊对话框发送按钮消息响应函数)
void CPriChatDlg::OnSend() 
{
	// TODO: Add your control notification handler code here
	SOCKADDR_IN priChatSock;	//定义地址结构体
	WSABUF wsabuf;				//定义数据发送缓冲
	DWORD dwSend;				//实际发送字节数
	int len;
	
	CString str,strTemp;
	GetDlgItemText(IDC_EDIT_SEND,str);
	if(""==str)
	{
		MessageBox("不能发送空消息!");
		return;
	}
	SetDlgItemText(IDC_EDIT_SEND,"");

	//GetDlgItemText(IDC_EDIT_RECV,strTemp);
	//显示你自己发送的信息
	strTemp=m_ptrDlg->m_ownHost+":\r\n"+str+"\r\n\r\n";
	//SetDlgItemText(IDC_EDIT_RECV,strTemp);
	SetRecvText(&strTemp);

	priChatSock.sin_family=AF_INET;
    //priChatSock.sin_addr.s_addr=m_addr.sin_addr.S_un.S_addr;
	priChatSock.sin_addr.s_addr=inet_addr(m_host_IP);	
		//目的地址为与此对话框相应的用户IP地址(正在与谁聊天则为谁的IP地址)
	priChatSock.sin_port=htons(55176);	//私聊端口

	//设定数据发送缓冲
	len=str.GetLength();
	wsabuf.buf=str.GetBuffer(len);
	wsabuf.len=len+1;
	
	//sendto(m_bSocket,smsg,256,0,(sockaddr*)&broadSock,sizeof(SOCKADDR));
	WSASendTo(m_ptrDlg->m_priSocket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&priChatSock,sizeof(SOCKADDR),NULL,NULL);
		//发送私聊数据
}


//将数据显示到接收编辑框的函数
void CPriChatDlg::SetRecvText(CString *pStr)
{
	CString str;
	GetDlgItemText(IDC_EDIT_RECV,str);	//取得编辑框文本
	str+=*pStr;							//加上新文本
	SetDlgItemText(IDC_EDIT_RECV,str);	//显示文本

	//使编辑框得滚动条自动滚动到最下面
	int nLen=((CEdit*)GetDlgItem(IDC_EDIT_RECV))->SendMessage(WM_GETTEXTLENGTH);
	((CEdit*)GetDlgItem(IDC_EDIT_RECV))->SetSel(nLen,nLen,FALSE);
}


//“传输文件”按钮的消息响应函数
void CPriChatDlg::OnBtnFileSend() 
{
	// TODO: Add your control notification handler code here
	CFileDialog	FileDlg(TRUE);	//建立打开文件对话框,让用户选择要发送的文件
	if(FileDlg.DoModal()!=IDOK)
		return;
	
	//CFile myFile;
	m_pathName=FileDlg.GetPathName();	//获取文件完整路径
	if(!m_myFile.Open(FileDlg.GetPathName(), CFile::modeRead | CFile::typeBinary))
	{
		AfxMessageBox("文件不存在!",MB_OK|MB_ICONERROR);
		return;
	}

	CString strTemp,m_fileTitle=FileDlg.GetFileName();	//保存文件名
	
	SOCKADDR_IN fileCtrlSendSock;	//定义地址结构体
	WSABUF wsabuf;					//定义数据发送缓冲
	DWORD dwSend;					//实际发送字节数
	int len;

	fileCtrlSendSock.sin_family=AF_INET;
    //priChatSock.sin_addr.s_addr=m_addr.sin_addr.S_un.S_addr;
	fileCtrlSendSock.sin_addr.s_addr=inet_addr(m_host_IP);	
		//目的地址为与此对话框相应的用户IP地址(正在与谁聊天则为谁的IP地址)
	fileCtrlSendSock.sin_port=htons(55178);		//文件传输控制命令端口

	//设定数据发送缓冲,为将要发送文件名
	len=m_fileTitle.GetLength();
	wsabuf.buf=m_fileTitle.GetBuffer(len);
	wsabuf.len=len+1;

	WSASendTo(m_ptrDlg->m_fileSocket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&fileCtrlSendSock,sizeof(SOCKADDR),NULL,NULL);
		//发送文件传输控制命令,请求对方接收文件

	//显示相关信息
	//GetDlgItemText(IDC_EDIT_RECV,strTemp);
	strTemp="你向"+m_host_name+"发送此文件:"+m_fileTitle+"\r\n\r\n";
	//SetDlgItemText(IDC_EDIT_RECV,strTemp);
	SetRecvText(&strTemp);

	FileButtonCtrl(0x00);
		//Disable“传输文件”、“接收文件”、“拒绝接收”和“退出”按钮
}


//控制“传输文件”按钮,“接收文件”和“拒绝接收”按钮的Enable和Disable
void CPriChatDlg::FileButtonCtrl(short ch)
{
	switch(ch)
	{
	case 0x60:	
		((CButton*)GetDlgItem(IDC_BTN_FILE_SEND))->EnableWindow(FALSE);
		((CButton*)GetDlgItem(IDC_BTN_FILE_RECV))->EnableWindow(TRUE);
		((CButton*)GetDlgItem(IDC_BTN_FILE_REFUSE))->EnableWindow(TRUE);
		((CButton*)GetDlgItem(IDCANCEL))->EnableWindow(FALSE);
		break;
	
	case 0x90:
		((CButton*)GetDlgItem(IDC_BTN_FILE_SEND))->EnableWindow(TRUE);
		((CButton*)GetDlgItem(IDC_BTN_FILE_RECV))->EnableWindow(FALSE);
		((CButton*)GetDlgItem(IDC_BTN_FILE_REFUSE))->EnableWindow(FALSE);
		((CButton*)GetDlgItem(IDCANCEL))->EnableWindow(TRUE);
		break;

	case 0x00:
		((CButton*)GetDlgItem(IDC_BTN_FILE_SEND))->EnableWindow(FALSE);
		((CButton*)GetDlgItem(IDC_BTN_FILE_RECV))->EnableWindow(FALSE);
		((CButton*)GetDlgItem(IDC_BTN_FILE_REFUSE))->EnableWindow(FALSE);
		((CButton*)GetDlgItem(IDCANCEL))->EnableWindow(FALSE);
		break;
	}	
}


//“接收文件”按钮的消息响应函数
void CPriChatDlg::OnBtnFileRecv() 
{
	// TODO: Add your control notification handler code here	


	
	CFileDialog	Dlg(FALSE,NULL,m_fileTitle,OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,NULL,this);
		//建立另存为对话框,让用户选择保存路径和文件名
	if(Dlg.DoModal()!=IDOK)
		return;
	
	m_savePathName=Dlg.GetPathName();
	/*FileButtonCtrl(0x00);
	
	CString strTemp;
	GetDlgItemText(IDC_EDIT_RECV,strTemp);
	strTemp+="文件传送中,请稍候。\r\n\r\n";
	SetDlgItemText(IDC_EDIT_RECV,strTemp);*/

	SOCKADDR_IN fileCtrlSendSock;	//定义地址结构体
	WSABUF wsabuf;					//定义数据发送缓冲
	DWORD dwSend;					//实际发送字节数
	int len;

	fileCtrlSendSock.sin_family=AF_INET;
    //priChatSock.sin_addr.s_addr=m_addr.sin_addr.S_un.S_addr;
	fileCtrlSendSock.sin_addr.s_addr=inet_addr(m_host_IP);
		//目的地址为与此对话框相应的用户IP地址(正在与谁聊天则为谁的IP地址)
	fileCtrlSendSock.sin_port=htons(55178);		//文件传输控制命令端口

	//设定数据发送缓冲,为“go”信息
	CString str="go";
	len=str.GetLength();
	wsabuf.buf=str.GetBuffer(len);
	wsabuf.len=len+1;

	WSASendTo(m_ptrDlg->m_fileSocket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&fileCtrlSendSock,sizeof(SOCKADDR),NULL,NULL);
		//发送文件传输控制命令,同意接收文件

	AfxBeginThread(FileRecvProc,this);	//启动文件接收线程

	/*注释部分为单线程模式
	Sleep(1000);
	//AfxSocketInit(NULL);
	CSocket sockClient;
	sockClient.Create();

	//CString	szIP;
	//GetDlgItemText(IDC_EDIT_IPADDRESS,szIP);
	
	if(!sockClient.Connect(m_host_IP, 800))
	{
		AfxMessageBox("连接到对方机器失败!");
		return;
	}

	
	SOCKET_STREAM_FILE_INFO StreamFileInfo;
	sockClient.Receive(&StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO));

	CFile destFile(Dlg.GetPathName(), CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);

	UINT dwRead = 0;
	while(dwRead<StreamFileInfo.nFileSizeLow)
	{
		byte* data = new byte[1024];
		memset(data,0,1024);

		UINT dw=sockClient.Receive(data, 1024);
		destFile.Write(data, dw);

		dwRead+=dw;
	}

	SetFileTime((HANDLE)destFile.m_hFile,&StreamFileInfo.ftCreationTime,
                &StreamFileInfo.ftLastAccessTime,&StreamFileInfo.ftLastWriteTime);
	destFile.Close();
	SetFileAttributes(StreamFileInfo.szFileTitle,StreamFileInfo.dwFileAttributes);
	sockClient.Close();
	
	GetDlgItemText(IDC_EDIT_RECV,strTemp);
	strTemp+="文件接收完毕!\r\n\r\n";
	SetDlgItemText(IDC_EDIT_RECV,strTemp);

	AfxMessageBox("接收完毕!");
	FileButtonCtrl(0x90);*/
}


//“拒绝接收”按钮的消息响应函数
void CPriChatDlg::OnBtnFileRefuse() 
{
	// TODO: Add your control notification handler code here
	SOCKADDR_IN fileCtrlSendSock;	//定义地址结构体
	WSABUF wsabuf;					//定义数据发送缓冲
	DWORD dwSend;					//实际发送字节数
	int len;

	fileCtrlSendSock.sin_family=AF_INET;
    //priChatSock.sin_addr.s_addr=m_addr.sin_addr.S_un.S_addr;
	fileCtrlSendSock.sin_addr.s_addr=inet_addr(m_host_IP);
		//目的地址为与此对话框相应的用户IP地址(正在与谁聊天则为谁的IP地址)
	fileCtrlSendSock.sin_port=htons(55178);		//文件传输控制命令端口

	//设定数据发送缓冲,为“stop”
	CString str="stop";
	len=str.GetLength();
	wsabuf.buf=str.GetBuffer(len);
	wsabuf.len=len+1;

	WSASendTo(m_ptrDlg->m_fileSocket,&wsabuf,1,&dwSend,0,(SOCKADDR*)&fileCtrlSendSock,sizeof(SOCKADDR),NULL,NULL);
		//发送文件传输控制命令,拒绝接收文件

	//显示相关信息
	str="你拒绝接收该文件\r\n\r\n";
	SetRecvText(&str);

	FileButtonCtrl(0x90);
		//Enable“传输文件”和“退出”按钮,Disable“接收文件”和“拒绝接收”按钮
}


//文件接收线程函数
UINT FileRecvProc(LPVOID lParam)
{
	CPriChatDlg *ptrPriChatDlg=(CPriChatDlg *)lParam;
		//取出收到的信息(指向保存接收方信息的CChatUser实例的指针)

		
	//显示相关信息
	CString strTemp;	
	strTemp="文件接收中,请稍候。\r\n\r\n";	
	ptrPriChatDlg->SetRecvText(&strTemp);
	ptrPriChatDlg->FileButtonCtrl(0x00);


	CSocket sockClient;			//建立异步套接字
	sockClient.Create();
	
	if(!sockClient.Connect(ptrPriChatDlg->m_host_IP, 55180))	//与发送方连接
	{
		AfxMessageBox("连接到对方机器失败!");
		return -1;
	}
	
	SOCKET_STREAM_FILE_INFO StreamFileInfo;		//定义描述文件信息结构体
	sockClient.Receive(&StreamFileInfo,sizeof(SOCKET_STREAM_FILE_INFO));//接收文件信息

	CFile destFile(ptrPriChatDlg->m_savePathName, CFile::modeCreate | CFile::modeWrite | CFile::typeBinary);
		//定义文件类,指明保存路径和操作方式

	DWORD dwReadlo=0;	//已发送大小的低双字
	DWORD dwReadhi=0;	//已发送大小的高双字
	DWORD present=0;	//已发送百分比
	unsigned __int64 temp1=(StreamFileInfo.nFileSizeHigh*2^32+StreamFileInfo.nFileSizeLow)/100;
		//文件大小的1/100
	unsigned __int64 temp2;

	//接收文件
	while(dwReadhi<=StreamFileInfo.nFileSizeHigh)
	{
		while(dwReadlo<StreamFileInfo.nFileSizeLow)
		{
			byte* data = new byte[1024];
			memset(data,0,1024);
			UINT dw=sockClient.Receive(data, 1024);	//接收1KB
			destFile.Write(data, dw);	//保存
			free(data);					//释放内存
			
			//ptrPriChatDlg->SetProgress(dwReadhi,dwReadlo,StreamFileInfo.nFileSizeHigh,StreamFileInfo.nFileSizeLow);
			
			dwReadlo+=dw;

			//更新文件接收进度
			if(0==StreamFileInfo.nFileSizeHigh)		//如果文件小于4GB
			{
				if(dwReadlo>=present*temp1)		//如果多传了1%
				{
					strTemp.Format("%d",present);
					ptrPriChatDlg->SetProgress(&strTemp,TRUE);	//更新进度
					present++;
				}
			}
			else		//如果文件大于4GB
			{
				temp2=dwReadhi*2^32+dwReadlo;		//已接收文件大小
				if(temp2>=present*temp1)			//如果多传了1%
				{
					strTemp.Format("%d",present);
					ptrPriChatDlg->SetProgress(&strTemp,TRUE);		//更新进度
					present++;
				}
			}
		}
		dwReadlo=0;
		dwReadhi++;
	}

	strTemp.Format("%d",100);		//接收完毕,将进度置为100%
	ptrPriChatDlg->SetProgress(&strTemp,TRUE);//更新进度

	SetFileTime((HANDLE)destFile.m_hFile,&StreamFileInfo.ftCreationTime,
                &StreamFileInfo.ftLastAccessTime,&StreamFileInfo.ftLastWriteTime);
		//设置文件时间
	destFile.Close();	//关闭文件
	SetFileAttributes(StreamFileInfo.szFileTitle,StreamFileInfo.dwFileAttributes);
		//设置文件属性
	sockClient.Close();		//关闭套接字
	
	//显示提示信息
	strTemp="文件接收完毕!\r\n\r\n";	
	ptrPriChatDlg->SetRecvText(&strTemp);

	//AfxMessageBox("接收完毕!");
	ptrPriChatDlg->FileButtonCtrl(0x90);
		//Enable“传输文件”和“退出”按钮,Disable“接收文件”和“拒绝接收”按钮

	ptrPriChatDlg->SetProgress(&strTemp,FALSE);		//清除文件进度显示
	return 0;
}


//显示文件传输进度函数
void CPriChatDlg::SetProgress(CString *str,BOOL b)
{
	if(b)
	{
		*str="已传送"+(*str)+"%";
		SetDlgItemText(IDC_PROGRESS,*str);
	}
	else
		SetDlgItemText(IDC_PROGRESS,"");
}

//关闭对话框(提供外部程序关闭对话框的方法)
void CPriChatDlg::CloseDlg()
{
	OnCancel();
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -