MFC:实现TCP通信,基础短信、文件传输功能

目录

一、先导

二、实现

服务端

客户端


源码地址:​​​​​​MFC:实现TCP通信,基础短信、文件传输功能

一、先导

来看效果:

894405c21f914de695d803f288e36bff.gif

 

 项目以PC作为服务器中转信息交流,适用于小型局域网内信息传输。

 

数据包的封装以及基础的套接字功能实现,请参考文章

包括CListenSocket及CClientSocket类的封装,关联主窗口。

数据包作出调整:

//StdPack.h
#pragma once

struct NETPACKAGE
{
	int len;
	int type;
	char buf[50000];
};

struct MESSAGEPACK
{
	int send;
	int recv;
	char message[49992];
};

当调用SendData(int len, int type, char * buf)函数后,

消息将发送至mRecvData(CClientSocket * pC),此时进行消息处理。


二、实现

服务端

1)新建项目,选择Window套接字功能

2)在项目属性,选择使用多字节字符集

94f16d35ef47480687e47d15d7677af4.png


// M_ServerDlg.h: 头文件
//

#pragma once

class CListenSocket;	//监听
class CClientSocket;	//传输

// CMServerDlg 对话框
class CMServerDlg : public CDialogEx
{
// 构造
public:
	CMServerDlg(CWnd* pParent = nullptr);	// 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_M_SERVER_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	void mAccept(CListenSocket*pL);      //接受连接时
	void mRecvData(CClientSocket*pC);    //接收数据时
	CListenSocket*pListen;	//监听
	CClientSocket*pClient;	//客户端
public:
	CList<CClientSocket*>list;	//存储CClientSocket列表
public:
	int m_port;			//端口号
	int m_max_listen;	//最大监听数
	afx_msg void OnBnClickedStart();
	afx_msg void OnBnClickedClose();
	CListCtrl m_list;	//客户端连接列表
	int FindPC(int recv);	//查找客户端(CClientSocket)
	int GetPC(int recv);	//获取客户端
	int SetId();		//生成初始Id
	CFile *file;		//缓存文件
	CString fpath;		//文件目录
	CString m_tpath;	//缓存目录
};
void CMServerDlg::mAccept(CListenSocket * pL)
{
    //接受连接
	pClient = new CClientSocket;
	pClient->SetDlg(this);
	pL->Accept(*pClient);

    //添加进客户端列表
	list.AddTail(pClient);
	int n = list.GetCount();
	CString str;
	str.Format(_T("%d"), n);
	m_list.InsertItem(n - 1, str);

    //生成并发送Id
	CString id;
	id.Format(_T("%d"), SetId());
	m_list.SetItemText(n - 1, 1, id);
	pClient->SendData(100, 1, (char*)id.GetBuffer(100));
}
void CMServerDlg::mRecvData(CClientSocket * pC)
{
	UpdateData(TRUE);
	NETPACKAGE pack;
	pC->GetPackage((char*)&pack);
	MESSAGEPACK mspk;
	memcpy(&mspk, pack.buf, sizeof(mspk));
	CString str;
	switch (pack.type)
	{
	case 1:    //信息转发
	{
		str.Format(_T("%d"), mspk.recv);
		int n = GetPC(_ttoi(str));
		if (n != -1)
		{
            //发送数据包至目标客户端
			pClient->SendData(50000, 2, (char*)&mspk);
            //通知原始客户端已发送
			pC->SendData(100, 3, "");
			return;
		}
        //目标客户端不存在
		pC->SendData(100, 4, "");
		break;
	}
	case 2:    //文件传输预处理
	{
		str.Format(_T("%d"), mspk.recv);
		int n = GetPC(_ttoi(str));
		if (n == -1)
		{
			pC->SendData(100, 4, "");
		}
		if (file != NULL)
		{
			pC->SendData(100, 5, "");
		}
		pC->SendData(100, 6, "");
        //通知目标准备接收文件
		pClient->SendData(10000, 7, (char*)&mspk);
		break;
	}
	case 3:    //准备接收文件
	{
		str.Format(_T("%s"), pack.buf);
		fpath = m_tpath + str;
		file = new CFile;
		file->Open(fpath, CFile::modeCreate
			| CFile::modeNoTruncate
			| CFile::modeWrite);
		break;
	}
	case 4:    //接收文件
		file->Write(pack.buf, pack.len);
		break;
	case 5:    //结束接收文件
	{
		file->Close();
		delete file;

        //读取缓存文件,
        //发送至客户端
		file = new CFile;
		file->Open(fpath, CFile::modeCreate
			| CFile::modeNoTruncate
			| CFile::modeRead);
		int len = 0;
		char *buf = new char[50000];
		do
		{
			len = file->Read(buf, 50000);
			pClient->SendData(len, 8, buf);
		} while (len > 0);
		pClient->SendData(100, 9, "");
		file->Close();
		delete file;
		delete buf;
		file = NULL;
		break;
	}
	}
	UpdateData(FALSE);
}
int CMServerDlg::FindPC(int recv)
{
	CString str;
	str.Format(_T("%d"), recv);
	for (int i = 0; i < list.GetCount(); i++)
	{
		if (str == m_list.GetItemText(i, 1))
		{
			return i;
		}
	}

	return -1;
}

int CMServerDlg::GetPC(int recv)
{
	int i = FindPC(recv);
	if (i == -1)
	{
		return -1;
	}
	pClient = list.GetAt(list.FindIndex(i));

	return 0;
}

int CMServerDlg::SetId()
{
    //生成四位伪随机数
	int rd = rand()*(9999 - 1000) / 32767 + 1000;    
	if (FindPC(rd) != -1)
	{
		SetId();
	}

	return rd;
}

客户端

布局及变量名参考:

cab7ead78c92487da906ffb371a04b7a.png


// M_ClientDlg.h: 头文件
//

#pragma once

class CClientSocket;

// CMClientDlg 对话框
class CMClientDlg : public CDialogEx
{
// 构造
public:
	CMClientDlg(CWnd* pParent = nullptr);	// 标准构造函数

// 对话框数据
#ifdef AFX_DESIGN_TIME
	enum { IDD = IDD_M_CLIENT_DIALOG };
#endif

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持


// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	void mRecvData(CClientSocket*pC);
	CClientSocket*pClient;
public:
	int AddintoList(int recv);
public:
	CString m_ipaddr;
	int m_port;
	afx_msg void OnBnClickedConnect();
	CListBox m_cust_list;
	int m_crt_id;
	int m_tag_id;
	CString m_space;
	CString m_ed_send;
	afx_msg void OnBnClickedSend();
public:
	CString m_fpath;        //文件目录
	CString m_fname;        //文件名
	CFile *file;            //缓存文件
	CString m_tpath;        //文件缓存目录
	afx_msg void OnBnClickedBrowse();
	afx_msg void OnBnClickedSendfile();
	void SendFile();
public:        //优化
	afx_msg void OnEnUpdateSpace();
	afx_msg void OnLbnDblclkCustList();
	virtual void OnOK();
};
void CMClientDlg::mRecvData(CClientSocket * pC)
{
	UpdateData(TRUE);
	NETPACKAGE pack;
	pC->GetPackage((char*)&pack);
	MESSAGEPACK mspk;
	memcpy(&mspk, pack.buf, sizeof(mspk));
	CString str;
	switch (pack.type)
	{
	case 1:    //接收并设置Id
	{
		str.Format(_T("%s"), pack.buf);
		m_crt_id = _ttoi(str);
		break;
	}
	case 2:    //接收文本信息
	{
		AddintoList(mspk.send);
		str.Format(_T("[%d]%s"), mspk.send, mspk.message);
		m_space += str;
		m_space += _T("\r\n");
		break;
	}
	case 3:     //信息发送已完成
	{
		AddintoList(m_tag_id);
		m_space += m_ed_send;
		m_space += _T("\r\n");
		m_ed_send = _T("");
		break;
	}
	case 4:
		MessageBox(_T("目标不存在"));
		break;
	case 5:
		MessageBox(_T("线路忙,请稍后重试"));
		break;
	case 6:
		SendFile();
		break;
	case 7:    //准备接收文件
	{
		AddintoList(mspk.send);
		str.Format(_T("[%d][接收文件]%s"), mspk.send, mspk.message);
		m_space += str;
		m_space += _T("\r\n");
		str.Format(_T("%s"), mspk.message);
		file = new CFile;
		file->Open(m_tpath + str, CFile::modeCreate
			| CFile::modeNoTruncate
			| CFile::modeWrite);
		break;
	}
	case 8:    //接收文件
		file->Write(pack.buf, pack.len);
		break;
	case 9:    //结束接收
		file->Close();
		delete file;
		file = NULL;
		break;
	}
	UpdateData(FALSE);
	OnEnUpdateSpace();
}
void CMClientDlg::OnBnClickedSend()
{
	UpdateData(TRUE);
	if (pClient == NULL)
	{
		MessageBox(_T("未连上服务器"));
		return;
	}
	if (m_tag_id < 1000 || m_tag_id>9999)
	{
		MessageBox(_T("目标不正确"));
		return;
	}
	MESSAGEPACK mspk;
	mspk.send = m_crt_id;
	mspk.recv = m_tag_id;
	memcpy(mspk.message, (char*)m_ed_send.GetBuffer(49992), 49992);
	pClient->SendData(50000, 1, (char*)&mspk);
	UpdateData(FALSE);
}


void CMClientDlg::OnBnClickedBrowse()
{
	UpdateData(TRUE);
	CFileDialog dlg(TRUE);
	if (dlg.DoModal() == IDOK)
	{
		m_fpath = dlg.GetPathName();
		m_fname = dlg.GetFileName();
	}
	UpdateData(FALSE);
}


void CMClientDlg::OnBnClickedSendfile()
{
	UpdateData(TRUE);
	if (m_fpath == _T(""))
	{
		MessageBox(_T("文件不为空"));
		return;
	}
	MESSAGEPACK mspk;
	mspk.send = m_crt_id;
	mspk.recv = m_tag_id;
	memcpy(mspk.message, (char*)m_fname.GetBuffer(9000), 9000);
	pClient->SendData(10000, 2, (char*)&mspk);
	AddintoList(m_tag_id);
}

void CMClientDlg::SendFile()
{
	pClient->SendData(100, 3, (char*)m_fname.GetBuffer(9000));
	file = new CFile;
	if (FALSE == file->Open(m_fpath, CFile::modeCreate
		| CFile::modeNoTruncate
		| CFile::modeRead))
	{
		MessageBox(_T("文件打开失败"));
		return;
	}
	int len = 0;
	char *buf = new char[50000];
	do
	{
		len = file->Read(buf, 50000);
		pClient->SendData(len, 4, buf);
	} while (len > 0);
	pClient->SendData(100, 5, "");
	CString str;
	str.Format(_T("[发送文件]%s"), m_fpath);
	m_space += str;
	m_space += _T("\r\n");
	UpdateData(FALSE);
	file->Close();
	delete file;
	delete buf;
}

项目优化 

void CMClientDlg::OnEnUpdateSpace()
{
    //当m_space更新后保持滚动条在底部
	CEdit *pEdit = (CEdit*)GetDlgItem(IDC_SPACE);
	pEdit->PostMessage(WM_VSCROLL, SB_BOTTOM, 0);
}


void CMClientDlg::OnLbnDblclkCustList()
{
    //双击m_cust_list更新至m_tag_id
	int n = m_cust_list.GetCurSel();
	CString str;
	m_cust_list.GetText(n, str);
	m_tag_id = _ttoi(str);
	UpdateData(FALSE);
}


void CMClientDlg::OnOK()
{
    //回车发送消息
	if (GetDlgItem(IDC_ED_SEND)->GetSafeHwnd() == ::GetFocus())
	{
		OnBnClickedSend();
	}

	//CDialogEx::OnOK();
}

 

 

 

 

  • 2
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
实现局域网内点对点的大文件传输,可以使用MFC(Microsoft Foundation Class)来编写一个Windows应用程序。 首先,要创建一个基于MFCC++项目,并利用MFC的Socket类来实现局域网内点对点的通信。可以使用TCP/IP协议来进行数据传输,因为TCP协议可以保证数据的可靠传输。 在编写程序时,需要创建一个Server端和一个Client端。Server端负责接收文件,并将文件发送给指定的Client端;Client端则负责接收文件。 在Server端,需要创建一个Socket并绑定到一个指定的端口上,然后监听来自Client端的连接请求。一旦有Client端连接进来,Server端就可以接收文件并将文件发送给Client端。 在Client端,需要创建一个Socket并连接到Server端指定的IP地址和端口上。然后将要传输的文件发送给Server端,并在接收完整个文件后保存到本地。 在编写程序时,需要考虑到大文件的传输可能会花费较长的时间,建议使用多线程来同时处理文件传输和UI交互,以避免程序在文件传输过程中出现卡顿现象。 另外,为了确保文件传输的安全性和完整性,可以在传输过程中使用校验和或者MD5校验等方法来验证文件的完整性。同时,在文件传输完成后,可以向双方发送确认消息以确保文件传输的成功。 通过以上步骤,就可以使用MFC实现局域网内点对点的大文件传输。希望我的回答能对你有所帮助!
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值