资源描述
目 录
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 程序流程
开始扫描
初始化
扫描单个端口?
T
m_bSinglePort=true;
m_cSinglePort.EnableWindow();
m_cPortFrom.EnableWindow(false);
m_cPortTo.EnableWindow(false);
m_cBtnStop.EnableWindow(false);
F
m_bSinglePort=false;
m_cSinglePort.EnableWindow(false);
m_cPortFrom.EnableWindow();
m_cPortTo.EnableWindow();
m_cBtnStop.EnableWindow(false);
设置端口
开始侦听端口
有错误?
显示结果
F
T
设置下一端口
扫描结束
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__INCLUDED_)
#define AFX_DLG_H__37F5060C_6D8B_42F0_90D9_FBA754BAD52B__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <io.h>
#include <afxsock.h>
//扫描结果
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 TestConnection(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();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
//给列表框加标题栏
AddHeader(_T("IP地址")); // 加一列标题栏字符
AddHeader(_T("端口号"));
AddHeader(_T("端口状态"));
AddHeader(_T("尝试连接次数"));
AddHeader(_T("标记"));
ShowHeaders();
//设置扫描单个端口
CheckRadioButton(IDC_RADIO1_SINGLE,IDC_RADIO2_RANGE,IDC_RADIO1_SINGLE);
//设置控件的默认状态
m_cSinglePort.EnableWindow();
m_cPortFrom.EnableWindow(false);
m_cPortTo.EnableWindow(false);
m_cBtnStop.EnableWindow(false);
m_cAttempts.SetWindowText(_T("1"));
return TRUE; // return TRUE unless you set the focus to a control
}
void CMyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{ if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{ CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{ CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CMyDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
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;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CMyDlg::OnQueryDragIcon()
{ return (HCURSOR) m_hIcon;
}
void CMyDlg::OnButton1Start() //“扫描”按钮
{ // TODO: Add your control notification handler code here
CString btnTxt,IP;
UINT nSinglePort;
BYTE f1,f2,f3,f4;
TCHAR temp[10]="\0";
m_cProgress.SetPos(0);
m_cResult.DeleteAllItems();
POSITION p=m_pStatusList->GetHeadPosition();
while(p)
{
POSITION temp=p;
DATA* pNode=(DATA*)m_pStatusList->GetNext(p);
m_pStatusList->RemoveAt(temp);
if (pNode)//pNode!=null
delete pNode;
}
if(m_cIP.IsBlank())
{ MessageBox("请输入主机IP地址");
return;
}
if(m_cIP.GetAddress(f1,f2,f3,f4)<4) {
MessageBox("请输入有效的IP地址");
return;
}
IP=_itoa(f1,temp,10);
IP+=_T('.');
IP+=_itoa(f2,temp,10);
IP+=_T('.');
IP+=_itoa(f3,temp,10);
IP+=_T('.');
IP+=_itoa(f4,temp,10);
m_cBtnStop.EnableWindow();
m_cBtnScan.EnableWindow(false);
if(m_bSinglePort)
{ CString port;
m_cSinglePort.GetWindowText(port);
m_minPort=m_maxPort=nSinglePort=atoi(port);
} else
{ CString port1,port2;
m_cPortFrom.GetWindowText(port1);
m_cPortTo.GetWindowText(port2);
m_minPort=atoi(port1);
m_maxPort=atoi(port2);
m_cProgress.SetRange32(0,m_maxPort-m_minPort+1); m_cProgress.SetStep(1);
}
if (!m_bSinglePort&&m_maxPort<m_minPort)
{
MessageBox(_T("您输入的端口范围有误,请重新输入"));
return;
}
UINT m_nMaxAttempts=GetDlgItemInt(IDC_EDIT4_ATTEMPTS);
for(m_nCounter=m_minPort;m_nCounter<=m_maxPort;m_nCounter++)
{
BOOL bIsOpen=false;
UINT nAttempt=1;
while(nAttempt<=m_nMaxAttempts && !bIsOpen)
{
TCHAR temp[10]="\0";
CString str=_T("尝试连接端口:");
str+=itoa(m_nCounter,temp,10);
str+=_T(", IP地址为=");
str+=IP;
str+=_T(", 尝试次数为=");
str+=itoa(nAttempt,temp,10);
CStatic* pStatic=(CStatic*)GetDlgItem(IDC_STATIC_STATUS);
pStatic->SetWindowText(str);
str.Empty();
bIsOpen=TestConnection(IP,m_nCounter);
if(bIsOpen)
{
DATA* pNode=new DATA;
ASSERT(pNode);
strcpy(pNode->IPAddress,IP.GetBuffer(IP.GetLength()));
strcpy(pNode->port,_itoa(m_nCounter,temp,10));
pNode->bStatus = 1; //open
pNode->nAttempts=nAttempt;
m_pStatusList->AddTail(pNode);
}
nAttempt++;
}
if (!bIsOpen)
{
DATA* pNode=new DATA;
ASSERT(pNode);
strcpy(pNode->IPAddress,IP.GetBuffer(IP.GetLength()));
strcpy(pNode->port,_itoa(m_nCounter,temp,10));
pNode->bStatus=0; //close
pNode->nAttempts=nAttempt-1;
m_pStatusList->AddTail(pNode);
}
MSG message;
if (::PeekMessage(&message,NULL,0,0,PM_REMOVE))
{
::TranslateMessage(&message);
::DispatchMessage(&me
展开阅读全文