目录
1 需求分析 (3)
1.1 课程设计目的 (3)
1.2 课程设计容 (3)
1.3 课程设计要求 (3)
2 概要设计 (3)
2.1 原理概述 (3)
2.2 运行环境 (3)
2.3 基本设计思路 (3)
2.4 功能模块设计 (3)
3 详细设计 (3)
3.1 程序流程 (3)
3.2 主要算法 (5)
3.3 主要数据结构 (6)
3.4 主要函数说明 (6)
4 用户使用手册 (7)
5 项目分析与总结 (7)
5.1 项目分析 (7)
5.2 总结与建议 (8)
附录A 源程序代码文件说明 (8)
附录B 参考文献 (20)
1.需求分析
1.1 课程设计目的
加深对TCP/IP的理解,熟悉socket编程。
课程设计容
实现一个扫描器,使用TCP connect进行端口扫描,并把扫描到的结果记录下来。
课程设计要求
(1)Windows或Linux环境下,程序在单机上运行;
(2)使用端口扫描对一台主机进行扫描,并显示出结果;对一个网段进行IP扫描,显示出结果;
(3)提供友好的用户界面。
2.概要设计
2.1 原理概述
TCP connect扫描是最基本的扫描,操作系统提供的connect()系统调用,用来与每一个感兴趣的目标计算机的端口进行连接。如果端口处于侦听状态,那么connect()就能成功。否则,这个端口是不能用的,即没有提供服务。
2.2 运行环境
Windows xp,VC++6.0
2.3 基本设计思路
创建一个CSocket套接字,通过CSocket的Connect函数测试该主机的某个端口是否能够连通,获得该端口的打开状态。
2.4 功能模块设计
(1)测试主机某个端口是否打开;
(2)“扫描结果”标题栏;
(3)扫描单个或多个端口的单选按钮;
(4)“扫描”,“停止”,“保存”按钮。
3.详细设计
3.1 程序流程
3.2 主要算法
(1)测试主机某个端口是否打开的函数TestConnection():
BOOL CMyDlg::TestConnection(CString IP,UINT nPort)
{ CSocket* pSocket;
pSocket=new CSocket;
ASSERT(pSocket);
if (!pSocket->Create())
{ delete pSocket;
pSocket=NULL;
return false;
}
while (!pSocket->Connect(IP,nPort))
{ delete pSocket;
pSocket=NULL;
return false;
}
pSocket->Close();
delete pSocket;
return true;
}
(2)响应单选按钮“扫描单个端口”和“扫描多个端口”的单击消息:
void CMyDlg::OnRadio1Single()
{ m_bSinglePort=true;
m_cSinglePort.EnableWindow();
m_cPortFrom.EnableWindow(false);
m_cPortTo.EnableWindow(false);
m_cBtnStop.EnableWindow(false);
}
void CMyDlg::OnRadio2Range()
{ m_bSinglePort=false;
m_cSinglePort.EnableWindow(false);
m_cPortFrom.EnableWindow();
m_cPortTo.EnableWindow();
m_cBtnStop.EnableWindow(false);
}
(3)显示列表框标题栏的成员函数:
//增加列表框标题栏的某一列
BOOL CMyDlg::AddColumn(LPCTSTR strItem,int nItem,int nSubItem,int nMask,int nFmt)
{ LV_COLUMN lvc;
lvc.mask=nMask;
lvc.fmt=nFmt;
lvc.pszText=(LPTSTR) strItem;
lvc.cx=m_cResult.GetStringWidth(lvc.pszText)+25;
if(nMask&LVCF_SUBITEM)
{ if(nSubItem!=-1)
lvc.iSubItem=nSubItem;
else
lvc.iSubItem=nItem;
}
return m_cResult.InsertColumn(nItem,&lvc);
}
//在列表框中加一条
BOOL CMyDlg::AddItem(int nItem,int nSubItem,LPCTSTR strItem ,int nImageIndex) { LV_ITEM lvItem;
lvItem.mask=LVIF_TEXT;
lvItem.iItem=nItem;
lvItem.iSubItem=nSubItem;
lvItem.pszText=(LPTSTR)strItem;
if(nImageIndex!=-1)
{ lvItem.mask|=LVIF_IMAGE;
lvItem.iImage|=LVIF_IMAGE;
}
if(nSubItem==0)
return m_cResult.InsertItem(&lvItem);
return m_cResult.SetItem(&lvItem);
}
//加一列标题栏字符
void CMyDlg::AddHeader(LPTSTR hdr)
{ if (m_pColumns)
m_pColumns->AddTail(hdr);
}
//显示列表框标题栏
void CMyDlg::ShowHeaders()
{ int nIndex=0;
POSITION pos=m_pColumns->GetHeadPosition();
while(pos)
{ CString hdr=(CString)m_pColumns->GetNext(pos);
AddColumn(hdr,nIndex++);
}
}
(4)“扫描”,“停止”,“保存”按钮,见附录程序。
3.3 主要数据结构及主要函数说明
(1)测试主机某个端口是否打开——TestConnection函数;
(2)“扫描结果”标题栏成员函数——AddHeader,AddColumn,ShowHeaders;在列表框中添加字符串的函数——AddItem;
(3)扫描单个或多个端口的单选按钮——OnRadioSingle()和
OnRadioRange();
(4)“扫描”,“停止”,“保存”按钮——OnButton1Start(),OnButton2Stop(),OnButton3Save();
4.用户使用手册
输入要扫描的主机IP地址,选择“扫描单个端口”或“扫描多个端口”,若选择前者,则输入单个端口号;若选择后者,则输入端口围。再输入扫描次数(默认值为1),单击“扫描”按钮,扫描结果列表框中将会显示所输入端口的扫描结果。单击“停止”时停在那一刻的状态,并显示已扫描的结果。单击“保存”时,可将结果保存在文本文件中。
5.项目分析与总结
5.1 项目分析
扫描单个端口的结果:
扫描多个端口:
通过观察,主机IP为10.5.104.36的25号端口是打开的。
5.2 总结与建议
通过这次实验,加深了对端口的理解,也对socket编程有了进一步的认识。实验中遇到许多函数和定义需要上网查阅资料,而且调试的过程也比较困难,需要向同学请教。所以,今后在编程和查阅资料方面的能力有待于进一步去提高。附录A
源程序代码文件说明:
(1)端口扫描Dlg.h:
#if !defined(AFX_DLG_H__37F5060C_6D8B_42F0_90D9_FBA754BAD52B__INCLUDE D_)
#define AFX_DLG_H__37F5060C_6D8B_42F0_90D9_FBA754BAD52B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include
#include
#include
#include
#include
//扫描结果
typedef struct
{ int nAttempts;
TCHAR IPAddress[16];
TCHAR port[5];
BOOL bStatus; //1 = open , 0 = close
}DATA;
/////////////////////////////////////////////////////////////////////////////
// CMyDlg dialog
class CMyDlg : public CDialog
{// Construction
public:
CMyDlg(CWnd* pParent = NULL); // standard constructor
// Dialog Data
//{{AFX_DATA(CMyDlg)
enum { IDD = IDD_MY_DIALOG };
CProgressCtrl m_cProgress;
CListCtrl m_cResult;
CIPAddressCtrl m_cIP;
CEdit m_cAttempts;
CEdit m_cPortTo;
CEdit m_cPortFrom;
CEdit m_cSinglePort;
CButton m_cBtnStop;
CButton m_cBtnScan;
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CMyDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL
// Implementation
protected:
HICON m_hIcon;
BOOL T estConnection(CString IP, UINT nPort);//测试主机某个端口是否打开
void ShowHeaders(void);//显示列表框标题栏
void AddHeader(LPTSTR hdr);//增加一列标题栏字符
AddItem(int nItem,int nSubItem,LPCTSTR strItem,int nImageIndex=-1);//向m_cResult输出一个结果
// 向输出结构列表控件增加一列
BOOL AddColumn(LPCTSTR strItem,int nItem,int nSubItem=-1,
int nMask=LVCF_FMT|LVCF_WIDTH|LVCF_TEXT|LVCF_SUBITEM,
int nFmt=LVCFMT_LEFT);
// 变量
UINT m_nMaxAttempts; //试图连接次数的最大值
BOOL m_bSinglePort; //是否只扫描单个端口
UINT m_minPort,m_maxPort; //扫描端口的围
UINT m_nCounter; //端口的个数
CStringList* m_pColumns; //列表框标题栏
CPtrList* m_pStatusList;//保存扫描结果的链表
// Generated message map functions
//{{AFX_MSG(CMyDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg void OnButton1Start();
afx_msg void OnButton2Stop();
afx_msg void OnButton3Save();
afx_msg void OnRadio1Single();
afx_msg void OnRadio2Range();
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif
// !defined(AFX_DLG_H__37F5060C_6D8B_42F0_90D9_FBA754BAD52B__INCLUDED _)
(2)端口扫描Dlg.cpp:
#include"stdafx.h"
#include"端口扫描.h"
#include"端口扫描Dlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
class CAboutDlg : public CDialog
{ public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support //}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CMyDlg dialog
CMyDlg::CMyDlg(CWnd* pParent /*=NULL*/)
: CDialog(CMyDlg::IDD, pParent)//在对话框的构造函数中初始化成员变量
{
//{{AFX_DATA_INIT(CMyDlg)
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
m_pColumns=new CStringList;
ASSERT(m_pColumns);
m_bSinglePort=true;
m_nMaxAttempts=1;
m_pStatusList=new CPtrList;
ASSERT(m_pStatusList);
}
void CMyDlg::DoDataExchange(CDataExchange* pDX)
{ CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CMyDlg)
DDX_Control(pDX, IDC_PROGRESS1, m_cProgress);
DDX_Control(pDX, IDC_LIST1, m_cResult);
DDX_Control(pDX, IDC_IPADDRESS1, m_cIP);
DDX_Control(pDX, IDC_EDIT4_ATTEMPTS, m_cAttempts);
DDX_Control(pDX, IDC_EDIT3_SINGLE_PORT_TO, m_cPortTo);
DDX_Control(pDX, IDC_EDIT2_SINGLE_PORT_FROM, m_cPortFrom);
DDX_Control(pDX, IDC_EDIT1_SINGLE_PORT, m_cSinglePort);
DDX_Control(pDX, IDC_BUTTON2_STOP, m_cBtnStop);
DDX_Control(pDX, IDC_BUTTON1_START, m_cBtnScan);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CMyDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1_START, OnButton1Start)
ON_BN_CLICKED(IDC_BUTTON2_STOP, OnButton2Stop)
ON_BN_CLICKED(IDC_BUTTON3_SAVE, OnButton3Save)
ON_BN_CLICKED(IDC_RADIO1_SINGLE, OnRadio1Single)
ON_BN_CLICKED(IDC_RADIO2_RANGE, OnRadio2Range)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
///////////////////////////////////////////////////////////////////////////// // CMyDlg message handlers
BOOL CMyDlg::OnInitDialog()//设置按钮的初始状态和列表框的风格{
CDialog::OnInitDialog();