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

                                                   前  言

基于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客户端进行测试。项目下载地址附文末。

 

                                                  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

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页