欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

【MFC实战项目】No.2 网络调试助手

程序员文章站 2022-05-23 12:47:04
...

                                                   前  言

基于MFC对话框开发了一款网络调试助手,只实现了TCP,还未实现UDP。某些功能与前面开发的串口调试助手原理相同,这里就不打算再做了。

VS版本:

Microsoft Visual Studio 2008 9.0.30729.1 SP

                                                  目  录

1.  软件成果展示

2.  源代码

(1)头文件  NetAssistDlg.h

(2)源文件 NetAssistDlg.cpp

3.  说明

4.   项目下载地址


                                            1.  软件成果展示

  这里同样使用铭心软体工作室出品的网络调试助手(V 3.7)进行测试。接着开软件分TCP服务器和TCP客户端进行测试。项目下载地址附文末。

【MFC实战项目】No.2 网络调试助手

【MFC实战项目】No.2 网络调试助手

 

                                                  2.  源代码

(1)头文件  NetAssistDlg.h


// NetAssistDlg.h : 头文件
//

#pragma once
#include "afxwin.h"
#include "afxcmn.h"

#include <ZySocket.h>
#include <vector>
using namespace std;

// CNetAssistDlg 对话框
class CNetAssistDlg : public CDialog
{
// 构造
public:
	CNetAssistDlg(CWnd* pParent = NULL);	// 标准构造函数

// 对话框数据
	enum { IDD = IDD_NETASSIST_DIALOG };

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

// 实现
protected:
	HICON m_hIcon;

	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()

/* ==================== function ======================= */
public:
	void InitMenu();									// 初始化菜单栏
	void InitNetSetting();								// 初始化网络设置
	void SetNetSetCtrlEnable(BOOL Enable = TRUE);		// 设置网络设置控件是否可编辑

	void ResizeRecvCtrl(BOOL bSmall = FALSE);			// 设置网络数据接收区控件大小
	void SetSerCtrlAreaVisable(BOOL bVisable = FALSE);	// 隐藏与显示控件
	void SetCliCtrlAreaVisable(BOOL bVisable = FALSE);	// 隐藏与显示控件

	void SetConectState(BOOL bConnect = FALSE);			// 设置连接状态
	void SetRecvNum();									// 接收字节数
	void SetSendNum();									// 发送字节数

	/* 连接/断开连接 */
	void UDPConOrDis();							// UDP
	void TCPSerConOrDis();						// TCP Server
	BOOL CheckPortIsOccupy(DWORD dwPort);		// 检测TCP端口是否被占用
	void TCPCliConOrDis();						// TCP Client

	CString GetIPAddr(CIPAddressCtrl *ipCtrl);	// 获取界面上的IP地址
	DWORD GetPort(CEdit *edtCtrl);				// 获取界面上的端口号

	void SetRecvData(CString strData);			// 设置接收区内容
	
	/* 发送消息 */
	void SendDataUdp(char *pszData);			// UDP发送数据
	void SendDataTcpServer(char *pszData);		// TCP Server发送数据
	void SendDataTcpClient(char *pszData);		// TCP CLient发送数据

	UINT findSocketInVector(SOCKET newSocket);			// 容器中查找端口号
	LRESULT OnShowTask(WPARAM wParam, LPARAM lParam);	// 托盘图标显示

public:
	CMenu m_Menu;
	int m_nRecvCount;
	int m_nSendCount;
	BOOL m_bConnect;

	// 套接字
	CServerSocket m_server;
	CClientSocket m_client;

	vector<SOCKET> m_VecSocket;		// 保存客户端套接字

public:
	CComboBox m_cmb_proToCol;		// 协议类型
	CIPAddressCtrl m_ipa_lochostIP;	// 本地IP地址/服务器IP地址
	CStatic m_pic_flag;				// 连接/未连接状态标识图片控件
	CEdit m_edt_locHostPort;		// 本地端口/服务器端口
	CButton m_btn_conDis;			// 连接/断开连接按钮
	CStatic m_edt_connectState;		// 状态栏连接/未连接标识
	CStatic m_edt_sendNum;			// 状态栏发送字节数
	CStatic m_edt_recvNum;			// 状态栏接收字节数
	CEdit m_edt_recvData;			// 网络数据接收
	CEdit m_edt_sendData;			// 发送区
	CButton m_ckb_send3;			// 发送完自动清空
	CButton m_ckb_recv2;			// 自动换行显示	
	CStatic m_stc_localIP;			// 本地IP
	CStatic m_stc_localPort;		// 本地端口
	CStatic m_stc_tarHost;			// 目标地址
	CStatic m_stc_tarPort;			// 目标端口
	CIPAddressCtrl m_ipa_tarHostIP;	// 目标IP地址
	CEdit m_edt_tarPort;			// 目标端口
	CStatic m_gpb_recvData;			// 网络数据接收
	CStatic m_stc_conTar;			// 连接对象
	CComboBox m_cmb_conTar;			// 连接对象
	CStatic m_stc_newCon;			// 状态栏 客户端连接/断开
	
public:
	afx_msg void OnBnClickedBtnClearnum();		// 状态栏复位按钮
	afx_msg void OnBnClickedBtnClrecv();		// 接受区清除显示
	afx_msg void OnBnClickedBtnClsend();		// 清除输入
	afx_msg void OnBnClickedBtnCondis();		// 连接/断开连接
	afx_msg void OnCbnSelchangeCmbProtocol();	// 协议类型改变

	afx_msg void OnClose();						// 窗口关闭响应函数
	afx_msg void OnBnClickedBtnSenddata();		// 发送数据
	afx_msg void OnMenuAboutBtnClicked();		// 菜单栏关于按钮
	afx_msg void OnMenuexitbtn();				// 菜单栏退出按钮
};

 

(2)源文件 NetAssistDlg.cpp


// NetAssistDlg.cpp : 实现文件
//

#include "stdafx.h"
#include "NetAssist.h"
#include "NetAssistDlg.h"

#include "Iphlpapi.h"
#include <malloc.h>
#include "Winsock2.h"
#include <stdlib.h>
#pragma comment(lib, "Iphlpapi.lib")
#pragma comment(lib, "ws2_32.lib")

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

NOTIFYICONDATA g_Tray;	// 托盘图标全局变量

CString g_strAddrAndPort;

// 套接字回调函数
// 服务器端
void SNewSocketCallBack(const SOCKADDR_IN *szSockAddr, SOCKET newSocket, void *pUserParam); // 客户端连接
void SNewMsgCallBack(const SOCKADDR_IN *pSockAddr, const SOCKET_HAND *pSocketHand, const SOCKET_DATA *pData, void *pUserParam); // 接收消息
void SCloseSocketCallBack(const char *szSocket, SOCKET newSocket, void *pUserParam); // 客户端断开连接

// 客户端
void CNewMsgCallBack(long nPort, SOCKET svrSocket, const SOCKET_DATA *pData, void *pUserParam); // 接收消息
void CDisconnetCallBack(void *pUsr); // 服务器断开连接

// 用于应用程序“关于”菜单项的 CAboutDlg 对话框

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// 对话框数据
	enum { IDD = IDD_ABOUTBOX };

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

// 实现
protected:
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()


// CNetAssistDlg 对话框




CNetAssistDlg::CNetAssistDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CNetAssistDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CNetAssistDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_CMB_PROTOCOL, m_cmb_proToCol);
	DDX_Control(pDX, IDC_IPA_LOCALHOSTIP, m_ipa_lochostIP);
	DDX_Control(pDX, IDC_STC_ICO, m_pic_flag);
	DDX_Control(pDX, IDC_EDT_LOCALHOSTPOR, m_edt_locHostPort);
	DDX_Control(pDX, IDC_BTN_CONDIS, m_btn_conDis);
	DDX_Control(pDX, IDC_STC_STATE, m_edt_connectState);
	DDX_Control(pDX, IDC_STC_SENDNUM, m_edt_sendNum);
	DDX_Control(pDX, IDC_STC_RECVNUM, m_edt_recvNum);
	DDX_Control(pDX, IDC_EDT_RECVDATA, m_edt_recvData);
	DDX_Control(pDX, IDC_EDT_SENDDATA, m_edt_sendData);
	DDX_Control(pDX, IDC_CK_SEND3, m_ckb_send3);
	DDX_Control(pDX, IDC_CK_RECV2, m_ckb_recv2);
	DDX_Control(pDX, IDC_STC_LOACLHOSTIP, m_stc_localIP);
	DDX_Control(pDX, IDC_STC_LOCALHOSTPOR, m_stc_localPort);
	DDX_Control(pDX, IDC_STC_TARHOST, m_stc_tarHost);
	DDX_Control(pDX, IDC_STC_TARPORT, m_stc_tarPort);
	DDX_Control(pDX, IDC_IPA_TARHOST, m_ipa_tarHostIP);
	DDX_Control(pDX, IDC_EDT_TARPORT, m_edt_tarPort);
	DDX_Control(pDX, IDC_STATIC_SERAILDATARECV, m_gpb_recvData);
	DDX_Control(pDX, IDC_EDT_TARPORT, m_edt_tarPort);
	DDX_Control(pDX, IDC_STC_CONTAR, m_stc_conTar);
	DDX_Control(pDX, IDC_CMB_CONTAR, m_cmb_conTar);
	DDX_Control(pDX, IDC_STC_NEWCONECT, m_stc_newCon);
}

BEGIN_MESSAGE_MAP(CNetAssistDlg, CDialog)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
	ON_BN_CLICKED(IDC_BTN_CLEARNUM, &CNetAssistDlg::OnBnClickedBtnClearnum)
	ON_BN_CLICKED(IDC_BTN_CLRECV, &CNetAssistDlg::OnBnClickedBtnClrecv)
	ON_BN_CLICKED(IDC_BTN_CLSEND, &CNetAssistDlg::OnBnClickedBtnClsend)
	ON_BN_CLICKED(IDC_BTN_CONDIS, &CNetAssistDlg::OnBnClickedBtnCondis)
	ON_CBN_SELCHANGE(IDC_CMB_PROTOCOL, &CNetAssistDlg::OnCbnSelchangeCmbProtocol)
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDC_BTN_SENDDATA, &CNetAssistDlg::OnBnClickedBtnSenddata)
	ON_COMMAND(ID_32773, &CNetAssistDlg::OnMenuAboutBtnClicked)
	ON_MESSAGE(WM_SHOWTASK, &CNetAssistDlg::OnShowTask) // 托盘图标
	ON_COMMAND(ID_MenuExitBtn, &CNetAssistDlg::OnMenuexitbtn)
END_MESSAGE_MAP()


// CNetAssistDlg 消息处理程序

LRESULT CNetAssistDlg::OnShowTask(WPARAM wParam, LPARAM lParam)
{
	if (wParam != IDR_MAINFRAME)
		return 1;

	if (lParam == WM_LBUTTONDBLCLK) // 左键点击托盘
	{
		this->ShowWindow(SW_SHOWNORMAL);
		this->SetForegroundWindow();
		Shell_NotifyIcon(NIM_DELETE, &g_Tray);
	}

	if (lParam == WM_RBUTTONDBLCLK) // 右键点击
	{
		// 右键弹出托盘菜单
		CMenu menu;
		menu.LoadMenu(IDR_MENU1);
		CMenu *pPopUp = menu.GetSubMenu(0);

		CPoint pt;
		GetCursorPos(&pt);
		SetForegroundWindow();
		pPopUp->TrackPopupMenu(TPM_RIGHTBUTTON, pt.x, pt.y, this);
		PostMessage(WM_NULL, 0, 0);
	}
	return 0;
}

BOOL CNetAssistDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// 将“关于...”菜单项添加到系统菜单中。

	// IDM_ABOUTBOX 必须在系统命令范围内。
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		BOOL bNameValid;
		CString strAboutMenu;
		bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
		ASSERT(bNameValid);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
	//  执行此操作
	SetIcon(m_hIcon, TRUE);			// 设置大图标
	SetIcon(m_hIcon, FALSE);		// 设置小图标

	// TODO: 在此添加额外的初始化代码
	/************************************************************************/
	/*                                                                      */
	/************************************************************************/
	this->InitMenu();
	this->InitNetSetting();
	this->SetConectState(FALSE);
	m_ckb_recv2.SetCheck(TRUE);

	m_nSendCount = 0;
	m_nRecvCount = 0;
	m_bConnect = FALSE;

	// 设置套接字回调函数
	m_server.m_pUserParam = this;
	m_server.NewSocketCallBack = SNewSocketCallBack;
	m_server.NewMsgCallBack = SNewMsgCallBack;
	m_server.CloseSocketCallBack = SCloseSocketCallBack;

	m_client.m_pUserParam = this;
	m_client.NewMsgCallBack = CNewMsgCallBack;
	m_client.DisconnetCall = CDisconnetCallBack;

	ResizeRecvCtrl(FALSE);
	SetSerCtrlAreaVisable(FALSE);
	SetCliCtrlAreaVisable(FALSE);
	m_cmb_conTar.AddString(_T("All Connections"));
	m_cmb_conTar.SetCurSel(0);

	/************************************************************************/
	/*                                                                      */
	/************************************************************************/
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

void CNetAssistDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if (nID == SC_MINIMIZE) // 最小化窗口
	{
		g_Tray.cbSize = (DWORD)sizeof(NOTIFYICONDATA);
		g_Tray.hWnd = this->m_hWnd;
		g_Tray.uID = IDR_MAINFRAME;
		g_Tray.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
		g_Tray.uCallbackMessage = WM_SHOWTASK; // 自定义的消息名称 
		g_Tray.hIcon = LoadIcon(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDR_MAINFRAME));
		lstrcpy(g_Tray.szTip, _T("网络调试助手 V1.0")); // 信息提示条
		Shell_NotifyIcon(NIM_ADD, &g_Tray); // 在托盘区添加图标 
		ShowWindow(SW_HIDE); // 隐藏主窗口 
		return;
	}

	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// 如果向对话框添加最小化按钮,则需要下面的代码
//  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
//  这将由框架自动完成。

void CNetAssistDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // 用于绘制的设备上下文

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// 使图标在工作区矩形中居中
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// 绘制图标
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

//当用户拖动最小化窗口时系统调用此函数取得光标
//显示。
HCURSOR CNetAssistDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

/************************************************************************/
/*                                                                      */
/************************************************************************/
// 加载菜单项
void CNetAssistDlg::InitMenu()
{
	m_Menu.LoadMenu( IDR_MENU1 );
	this->SetMenu(&m_Menu);
}

void CNetAssistDlg::InitNetSetting()
{
	// 协议类型
	m_cmb_proToCol.AddString(_T("UDP"));
	m_cmb_proToCol.AddString(_T("TCP Server"));
	m_cmb_proToCol.AddString(_T("TCP Client"));
	m_cmb_proToCol.SetCurSel(0);

	// 本地IP地址
	char *pszLocIp = m_server.GetLocalIP();
	if (pszLocIp = "0.0.0.0")
		pszLocIp = "127.0.0.1";
	m_ipa_lochostIP.SetWindowText(pszLocIp);

	// 本地端口号
	m_edt_locHostPort.SetWindowText(_T("8080"));
}

// 设置网络设置控件是否可编辑
void CNetAssistDlg::SetNetSetCtrlEnable(BOOL Enable)
{
	m_cmb_proToCol.EnableWindow(Enable);
	m_ipa_lochostIP.EnableWindow(Enable);
	m_edt_locHostPort.EnableWindow(Enable);
}

void CNetAssistDlg::ResizeRecvCtrl(BOOL bSmall)
{
	// 获取消息接收区控件在窗口客户区的坐标及大小
	CRect rectGpb, rectEdt;
	m_gpb_recvData.GetWindowRect(&rectGpb);
	m_edt_recvData.GetWindowRect(&rectEdt);
	ScreenToClient(&rectGpb);
	ScreenToClient(&rectEdt);

	rectGpb.bottom = bSmall ? 425 : 495;
	rectEdt.bottom = bSmall ? 420 : 490;

	m_gpb_recvData.MoveWindow(&rectGpb);
	m_edt_recvData.MoveWindow(&rectEdt);
}

void CNetAssistDlg::SetSerCtrlAreaVisable(BOOL bVisable)
{
	m_stc_conTar.ShowWindow(bVisable);
	m_cmb_conTar.ShowWindow(bVisable);
}

void CNetAssistDlg::SetCliCtrlAreaVisable(BOOL bVisable)
{
	m_stc_tarHost.ShowWindow(bVisable);
	m_stc_tarPort.ShowWindow(bVisable);
	m_ipa_tarHostIP.ShowWindow(bVisable);
	m_edt_tarPort.ShowWindow(bVisable);

	if ( bVisable )
	{
		char *pszLocIp = m_server.GetLocalIP();
		if (pszLocIp = "0.0.0.0")
			pszLocIp = "127.0.0.1";
		m_ipa_tarHostIP.SetWindowText(pszLocIp);
	}
}

// 设置连接/断开图片标识,连接/断开按钮,状态栏连接状态
void CNetAssistDlg::SetConectState(BOOL bConnect)
{
	HICON hIcon;
	CString strBtn, strEdt;
	if ( bConnect )
	{
		hIcon = AfxGetApp()->LoadIcon( IDI_ICN_CONNECT );
		strBtn = _T("断开");
		strEdt = _T("已连接");
	}
	else
	{
		hIcon = AfxGetApp()->LoadIcon( IDI_ICN_DISCON );
		strBtn = _T("连接");
		strEdt = _T("未连接");
	}

	m_pic_flag.SetIcon(hIcon);
	m_btn_conDis.SetWindowText(strBtn);
	m_edt_connectState.SetWindowText(_T("连接状态:") + strEdt);
}

// 接收字节数
void CNetAssistDlg::SetRecvNum()	
{
	CString strRecvNum;
	strRecvNum.Format("%d", m_nRecvCount);
	m_edt_recvNum.SetWindowText(_T("接收:") + strRecvNum);
}

// 发送字节数
void CNetAssistDlg::SetSendNum()	
{
	CString strSendNum;
	strSendNum.Format("%d", m_nSendCount);
	m_edt_sendNum.SetWindowText(_T("发送:") + strSendNum);
}

// 复位计数
void CNetAssistDlg::OnBnClickedBtnClearnum()
{
	m_nRecvCount = 0;
	m_nSendCount = 0;
	SetRecvNum();
	SetSendNum();
}

// 清除显示
void CNetAssistDlg::OnBnClickedBtnClrecv()
{
	m_edt_recvData.SetWindowText(_T(""));
}

// 清除输入
void CNetAssistDlg::OnBnClickedBtnClsend()
{
	m_edt_sendData.SetWindowText(_T(""));
}

// 协议类型改变
void CNetAssistDlg::OnCbnSelchangeCmbProtocol()
{
	CString strLocalIP;
	CString strLocalPort;
	// TCP Client
	if (m_cmb_proToCol.GetCurSel() == 2)
	{
		strLocalIP = _T("(2)服务器IP地址");
		strLocalPort = _T("(3)服务器端口");
	}
	else
	{
		strLocalIP = _T("(2)本地IP地址");
		strLocalPort = _T("(3)本地端口号");
	}

	m_stc_localIP.SetWindowText(strLocalIP);
	m_stc_localPort.SetWindowText(strLocalPort);
}

/************************************************************************/
/*                            连接/断开连接                         */
/************************************************************************/

// 连接/断开
void CNetAssistDlg::OnBnClickedBtnCondis()
{
	switch (m_cmb_proToCol.GetCurSel())
	{
	case 0: //UDP
		UDPConOrDis();
		break;
	case 1:	// TCP Server
		TCPSerConOrDis();
		break;
	case 2:	// TCP Client
		TCPCliConOrDis();
		break;
	default:
		break;
	}
}

// UDP
void CNetAssistDlg::UDPConOrDis()
{
	m_stc_tarHost.SetWindowText(_T("目标主机:"));
	m_stc_tarPort.SetWindowText(_T("目标端口:"));
	return;
}

// TCP Server
void CNetAssistDlg::TCPSerConOrDis()
{
	// 已连接的情况下,断开连接
	if ( m_bConnect ) 
	{
		if ( m_server.StopListening() ) // 停止监听
		{
			SetRecvData(_T("服务器已断开连接!\r\n"));
			m_bConnect = FALSE;
			SetConectState(FALSE);
			m_cmb_conTar.ResetContent();
			m_cmb_conTar.AddString(_T("All Connections"));
			m_cmb_conTar.SetCurSel(0);

			SetNetSetCtrlEnable(TRUE);
			ResizeRecvCtrl(FALSE);
			SetSerCtrlAreaVisable(FALSE);
		}
		else
		{
			SetRecvData(_T("服务器断开连接错误!\r\n"));
		}
		return;
	}// if (m_bConnect)

	// 未连接的情况下,连接
	if ( !m_bConnect )
	{
		DWORD dwPort = GetPort(&m_edt_locHostPort);
		// 检测端口是否被占用
		if ( CheckPortIsOccupy(dwPort) )
		{
			SetRecvData(_T("创建服务器失败,端口已被其它应用程序占用!\r\n"));
			return;
		}

		if ( m_server.StartListening(dwPort, TCP_TYPE) )
		{
			SetRecvData(_T("服务器已创建!\r\n"));
			m_bConnect = TRUE;
			SetConectState(TRUE);

			SetNetSetCtrlEnable(FALSE);
			ResizeRecvCtrl(TRUE);
			SetSerCtrlAreaVisable(TRUE);
			//SetCliCtrlAreaVisable(FALSE);
		}
		else
		{
			SetRecvData(_T("创建服务器失败!\r\n"));
		}
		return;
	}// if (!m_bConnect)
}

// 遍历本地tcp端口 被占用返回TRUE,否则返回FALSE
BOOL CNetAssistDlg::CheckPortIsOccupy(DWORD dwPort)
{
	PMIB_TCPTABLE pTcptable;
	pTcptable = (MIB_TCPTABLE*)malloc(sizeof(MIB_TCPTABLE));
	DWORD dwsize = sizeof(MIB_TCPTABLE);
	if (GetTcpTable(pTcptable, &dwsize, 2) == ERROR_INSUFFICIENT_BUFFER)
	{
		free(pTcptable);
		pTcptable = (PMIB_TCPTABLE)malloc(dwsize); 
	}

	if (GetTcpTable(pTcptable, &dwsize, 2) == NO_ERROR)
	{
		for (int i = 0; i < (int)pTcptable->dwNumEntries; i++)
		{
			DWORD port = ntohs(pTcptable->table[i].dwLocalPort);
			if (port == dwPort)
			{
				return TRUE;
			} 
		}
	} 

	free(pTcptable);
	return FALSE;
}

// TCP Client
void CNetAssistDlg::TCPCliConOrDis()
{
	// 已连接的情况下,断开连接
	if ( m_bConnect )
	{
		m_client.CloseSocket();
		if ( !m_client.IsConnect() )
		{
			SetRecvData(_T("已与服务器断开连接!\r\n"));
			m_bConnect = FALSE;
			SetConectState(FALSE);

			SetNetSetCtrlEnable(TRUE);
			ResizeRecvCtrl(FALSE);
			SetCliCtrlAreaVisable(FALSE);
		}
		else
		{
			SetRecvData(_T("断开连接失败!\r\n"));
		}
		return;
	}

	// 未连接的情况下,连接
	if ( !m_bConnect )
	{
		m_client.SetSockType(TCP_TYPE);

		// 获取IPAddrCtrl中的地址
		CString strIP = GetIPAddr(&m_ipa_lochostIP);
		char *szIp = strIP.GetBuffer(0);
		strIP.ReleaseBuffer();
		
		// 获取端口号
		DWORD dwPort = GetPort(&m_edt_locHostPort);

		if ( m_client.ConnectServer(szIp, dwPort) )
		{
			SetRecvData(_T("连接服务器成功!\r\n"));
			m_bConnect = TRUE;
			SetConectState(TRUE);

			SetNetSetCtrlEnable(FALSE);
			ResizeRecvCtrl(TRUE);
			SetCliCtrlAreaVisable(TRUE);

			m_stc_tarHost.SetWindowText(_T("本地主机:"));
			m_stc_tarPort.SetWindowText(_T("本地端口:"));
		}
		else
		{
			SetRecvData(_T("连接服务器失败!\r\n"));
		}
		return;
	}
}

// 获取IP
CString CNetAssistDlg::GetIPAddr(CIPAddressCtrl *ipCtrl)
{
	BYTE byField0, byField1, byField2, byField3;
	ipCtrl->GetAddress(byField0, byField1, byField2, byField3);
	CString strIP;
	strIP.Format("%d.%d.%d.%d", byField0, byField1, byField2, byField3);
	return strIP;
}

// 获取端口号
DWORD CNetAssistDlg::GetPort(CEdit *edtCtrl)
{
	CString strPort;
	edtCtrl->GetWindowText(strPort);
	int nPort = _ttoi(strPort);
	return (DWORD)nPort;
}

// 设置接收区内容
void CNetAssistDlg::SetRecvData(CString strData)
{
	CString strOld;
	m_edt_recvData.GetWindowText(strOld);	

	char buff[128];
	int nCount = m_edt_recvData.GetLine( m_edt_recvData.GetLineCount() - 1, buff, 128);
	if ( m_ckb_recv2.GetCheck() && nCount != 0)
		strData = _T("\r\n") + strData;
	strOld += strData;
	m_edt_recvData.SetWindowText(strOld);

	int nLineCount = m_edt_recvData.GetLineCount();
	m_edt_recvData.LineScroll(nLineCount - 1); // 设置滚动条一直在底部
}

// 发送信息
void CNetAssistDlg::OnBnClickedBtnSenddata()
{
	if ( !m_bConnect )
	{
		AfxMessageBox(_T("网络未连接,发送失败!"));
		return;
	}

	CString strData;
	m_edt_sendData.GetWindowText(strData);
	char *pszData = strData.GetBuffer(0);
	strData.ReleaseBuffer();

	switch (m_cmb_proToCol.GetCurSel())
	{
	case 0: // UDP
		SendDataUdp(pszData);
		break;
	case 1: // TCP Server
		SendDataTcpServer(pszData);
		break;
	case 2: // TCP Client
		SendDataTcpClient(pszData);
		break;
	default:
		break;
	}

	// 发送完自动清空
	if ( m_ckb_send3.GetCheck() )
		m_edt_sendData.SetWindowText(_T(""));
}

// 发送消息
// UDP
void CNetAssistDlg::SendDataUdp(char *pszData)
{
	AfxMessageBox(_T("UDP通信暂不可用!"));
}

// TCP Server
void CNetAssistDlg::SendDataTcpServer(char *pszData)
{
	if (pszData == NULL)
		return;

	UINT nLen = strlen(pszData);

	int nItem = m_cmb_conTar.GetCurSel();
	if (nItem == 0) // All Connections
	{
		for (UINT i = 0; i < m_VecSocket.size(); i++)
		{
			long nSendRet = m_server.SendData(m_VecSocket.at(i), pszData, nLen);
			if (nSendRet < 0)
			{
				SetRecvData(_T("\r\n发送消息失败!"));
				continue;
			}
			m_nSendCount += nLen;
			SetSendNum();
		}
	}
	else
	{
		long nSendRet = m_server.SendData(m_VecSocket.at(nItem-1), pszData, nLen);
		if (nSendRet < 0)
		{
			SetRecvData(_T("\r\n发送消息失败!"));
			return;
		}
		m_nSendCount += nLen;
		SetSendNum();
	}
}

// TCP Client
void CNetAssistDlg::SendDataTcpClient(char *pszData)
{
	if (pszData == NULL)
		return;

	UINT nLen = strlen(pszData);
	int nSendRet = m_client.SendData(pszData, nLen);
	if (nSendRet <= 1)
	{
		SetRecvData(_T("\r\n发送消息失败!"));
		return;
	}
	m_nSendCount += nLen;
	SetSendNum();
}

/************************************************************************/
/*                           套接字回调函数                         */
/************************************************************************/

// 服务器端 Server
// 客户端连接
void SNewSocketCallBack(const SOCKADDR_IN *szSockAddr, SOCKET newSocket, void *pUserParam)
{
	CNetAssistDlg *p = (CNetAssistDlg *)pUserParam;
	p->m_VecSocket.push_back(newSocket);

	CString strAddr = inet_ntoa(szSockAddr->sin_addr); // 得到发送者IP地址
	char szPort[6];
	itoa(szSockAddr->sin_port, szPort, 10);	// 得到发送者本地端口
	CString strAddrPort = strAddr + _T(":") + szPort;
	p->m_cmb_conTar.AddString(strAddrPort);

	p->m_stc_newCon.SetWindowText(_T("New Connection:") + strAddrPort);
}

// 接收消息
void SNewMsgCallBack(const SOCKADDR_IN *pSockAddr, const SOCKET_HAND *pSocketHand, const SOCKET_DATA *pData, void *pUserParam)
{
	CNetAssistDlg *p = (CNetAssistDlg *)pUserParam;

	CString strAddr = inet_ntoa(pSockAddr->sin_addr); // 得到发送者IP地址
	char szPort[6];
	itoa(pSockAddr->sin_port, szPort, 10);	// 得到发送者本地端口
	CString strAddrPort = strAddr + _T(":") + szPort;

	CString strAddrPortOld = g_strAddrAndPort;
	g_strAddrAndPort = strAddrPort;
	if (strAddrPortOld != strAddrPort)
	{
		p->SetRecvData(_T("【Receive from ") + strAddrPort + _T("】:\r\n"));
	}
	p->SetRecvData(pData->pData);

	p->m_nRecvCount += pData->len;
	p->SetRecvNum();
}

// 客户端断开连接
void SCloseSocketCallBack(const char *szSocket, SOCKET newSocket, void *pUserParam)
{
	CNetAssistDlg *p = (CNetAssistDlg *)pUserParam;
	p->m_stc_newCon.SetWindowText(szSocket);
	
	if (p->m_VecSocket.empty())
		return;

	UINT nItem = p->findSocketInVector(newSocket);
	if (nItem != -1)
	{
		p->m_cmb_conTar.DeleteString(nItem+1);
		p->m_cmb_conTar.SetCurSel(nItem);
	}
}

// 返回-1表示失败,否则返回索引
UINT CNetAssistDlg::findSocketInVector(SOCKET newSocket)
{
	UINT nItem = -1;
	UINT i = 0;
	for (vector<SOCKET>::iterator it = m_VecSocket.begin(); it != m_VecSocket.end(); )
	{
		if (*it == newSocket)
		{
			m_VecSocket.erase(it);
			nItem = i;
			break;
		}
		it++;
		i++;
	}

	return nItem;
}

// 客户端 Client
// 接收消息
void CNewMsgCallBack(long nPort, SOCKET svrSocket, const SOCKET_DATA* pData, void * pUserParam)
{
	CNetAssistDlg *p = (CNetAssistDlg *)pUserParam;
	p->SetRecvData(pData->pData);
	p->m_nRecvCount += pData->len;
	p->SetRecvNum();

	CString strPort;
	strPort.Format("%d", nPort);
	p->m_edt_tarPort.SetWindowText(strPort);
}

// 服务器断开连接
void CDisconnetCallBack(void *pUsr)
{
	AfxMessageBox("此函数为什么不会响应??");
	CNetAssistDlg *p = (CNetAssistDlg *)pUsr;
	p->SetRecvData(_T("\r\n服务器已下线!"));
	p->OnBnClickedBtnCondis();
}

// 串口关闭前,判断套接字是否关闭
void CNetAssistDlg::OnClose()
{
	m_server.StopListening();
	if (m_client.IsConnect())
		m_client.CloseSocket();

	CDialog::OnClose();
}


void CNetAssistDlg::OnMenuAboutBtnClicked()
{
	CAboutDlg dlg;
	dlg.DoModal();
}

void CNetAssistDlg::OnMenuexitbtn()
{
	EndDialog(0);
}

 

                                                    3.  说明

CServerSocket类和CClientSocket类是对socket的封装,该类由动态链接库导出,这里不提供源码,项目里有该动态链接库的头文件和相应的DLL和LIB文件,下载地址请转至文末查看。

 

                                              4.   项目下载地址

https://download.csdn.net/download/wu9797/10562075

相关标签: MFC