计算机网络与通信课程设计获取主机名和IP地址.docx
《计算机网络与通信课程设计获取主机名和IP地址.docx》由会员分享,可在线阅读,更多相关《计算机网络与通信课程设计获取主机名和IP地址.docx(17页珍藏版)》请在冰豆网上搜索。
计算机网络与通信课程设计获取主机名和IP地址
1绪言
MicrosoftVisualC++是Microsoft公司推出的开发Win32环境程序,面向对象的可视化集成编程系统。
它不但具有程序框架自动生成、灵活方便的类管理、代码编写和界面设计集成交互操作、可开发多种程序等优点,而且通过简单的设置就可使其生成的程序框架支持数据库接口、OLE2,WinSock网络、3D控制界面。
它以拥有“语法高亮”,IntelliSense(自动完成功能)以及高级除错功能而著称。
比如,它允许用户进行远程调试,单步执行等。
还有允许用户在调试期间重新编译被修改的代码,而不必重新启动正在调试的程序。
其编译及建置系统以预编译头文件、最小重建功能及累加连结著称。
这些特征明显缩短程式编辑、编译及连结花费的时间,在大型软件计划上尤其显著。
在网络编程中,像获取主机名和IP地址这样的基本应用是必不可少的,这些基本的应用通过适当改变可以很容易地应用到网络软件中。
因此,获取主机名和IP地址是用现实意义的。
2方案的论证及选择
方案一:
用WindowsAPI进行设计。
WindowsAPI可以很容易获取主机名和IP地址,但是在窗口设计是却显得比较繁琐。
方案二:
用MFC进行设计。
用MFC设计可以更容易的设计显示界面,在获取主机名和IP地址方面也比不复杂。
综上,选择方案二。
3重要结构和函数
3.1函数gethostname
函数原型为:
intgethostname(char*name,intnamelen);
其中,参数name是一个指向将要存放主机名的缓冲区的指针,namelen用于指定缓冲区的长度。
该函数把本地主机名存放入由name参数指定的缓冲区中。
返回的主机名是一个以NULL结束的字符串。
主机名的形式取决于WindowsSockets实现-它可能是一个简单的主机名,或者是一个域名。
然而,返回的名字必定可以在gethostbyname()和WSAAsyncGetHostByName()中使用。
如果没有错误发生,gethostname()返回0。
否则它返回SOCKET_ERROR。
3.2函数gethostbyname
函数原型为:
structhostent*gethostbyname(constchar*addr);
其中,addr为指向主机名的指针,它一般有函数gethostname返回。
该函数返回对应于给定主机名的包含主机名字和地址信息的hostent结构指针,该结构的格式如下:
structhostent{
char*h_name;
char**h_aliases;
inth_addrtype;
inth_length;
char**h_addr_list;
#defineh_addrh_addr_list[0]
};
其中,h_name是地址的正式名称;h_aliases是空字节-地址的预备名称的指针;h_addrtype地址类型,通常是AF_INET;h_length地址的比特长度;h_addr_list是零字节-主机网络地址指针;网络字节顺序;h_addr-h_addr_list中的第一地址。
需要注意的是gethostbyname()函数属于WinSockAPI库,而在使用WinSockAPI之前,必须调用WSA-Startup函数,只有该函数成功返回(表示应用程序与WinSock库成功地建立起连接),应用程序才可以调用其他WindowsSocketsDLL中的函数。
当程序将要结束时,又必须调用WSACleanup函数进行清理工作,以便释放其占用的资源。
WSACleanup函数用来结束WindowsSocketsDLL的使用。
3.3函数inet_ntoa
函数原型为:
charFAR*inet_ntoa(structin_addrin);
该函数将一个IP转换成一个互联网标准点分格式的字符串,in为一个表示Internet主机地址的结构。
如果正确,返回一个字符指针,指向一块存储着点分格式IP地址的静态缓冲区(同一线程内共享此内存);错误,返回NULL。
3.4函数TextOut
函数原型为:
BOOLTextOut(
HDChdc,
intnXStart,
intnYStart,
LPCTSTRlpString,
intcbString
);
Hdc:
设备环境的句柄
nXStart:
指定用于字符串对齐的基准点的逻辑X坐标。
nYStart:
指定用于字符串对齐的基准点的逻辑Y坐标。
lpString:
指向将被绘制字符串的指针。
此字符串不必为以\0结束的,因为cbString中指定了字符串的长度。
cbString:
指定了字符串的长度。
该函数用当前选择的字体、背景颜色和正文颜色将一个字符串写到指定位置。
如果函数调用成功,返回值为非零值。
如果函数调用失败,返回值为0。
3.5函数memcpy
函数原型为:
void*memcpy(void*dest,constvoid*src,size_tn);
该函数从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中。
3.6WSAData结构
结构原型为:
structWSAData{
WORDwVersion;
WORDwHighVersion;
charszDescription[WSADESCRIPTION_LEN+1];
charszSystemStatus[WSASYSSTATUS_LEN+1];
unsignedshortiMaxSockets;
unsignedshortiMaxUdpDg;
char*lpVendorInfo;
};
wVersion:
WindowsSocketsDLL期望调用者使用的WindowsSockets规范的版本。
高位字节存储副版本号,低位字节存储主版本号,可以用WORDMAKEWORD(BYTE,BYTE)返回这个值,例如:
MAKEWORD(1,1)
wHighVersion:
这个DLL能够支持的WindowsSockets规范的最高版本。
通常它与wVersion相同。
szDescription:
以null结尾的ASCII字符串,WindowsSocketsDLL将对WindowsSockets实现的描述拷贝到这个字符串中,包括制造商标识。
文本(最多可以有256个字符)可以包含任何字符,但是要注意不能包含控制字符和格式字符,应用程序对其最可能的使用方式是把它(可能被截断)显示在在状态信息中。
szSystemStatus:
以null结尾的ASCII字符串,WindowsSocketsDLL把有关的状态或配置信息拷贝到该字符串中。
WindowsSocketsDLL应当仅在这些信息对用户或支持人员有用时才使用它们,它不应被作为szDescription域的扩展。
iMaxSockets:
单个进程能够打开的socket的最大数目。
WindowsSockets的实现能提供一个全局的socket池,可以为任何进程分配;或者它也可以为socket分配属于进程的资源。
这个数字能够很好地反映WindowsSocketsDLL或网络软件的配置方式。
应用程序的编写者可以通过这个数字来粗略地指明WindowsSockets的实现方式对应用程序是否有用。
例如,XWindows服务器在第一次启动的时候可能会检查iMaxSockets的值:
如果这个值小于8,应用程序将显示一条错误信息,指示用户重新配置网络软件(这是一种可能要使用szSystemStatus文本的场合)。
显然无法保证某个应用程序能够真正分配iMaxSockets个socket,因为可能有其它WindowsSockets应用程序正在使用。
iMaxUdpDg:
WindowsSockets应用程序能够发送或接收的最大的用户数据包协议(UDP)的数据包大小,以字节为单位。
如果实现方式没有限制,那么iMaxUdpDg为零。
在Berkeleysockets的许多实现中,对于UDP数据包有个固有的限制(在必要时被分解),大小为8192字节。
WindowsSockets的实现可以对碎片重组缓冲区的分配作出限制。
对于适合的WindowsSockets实现,iMaxUdpDg的最小值为512。
注意不管iMaxUdpDg的值是什么,都不推荐你发回一个比网络的最大传送单元(MTU)还大的广播数据包。
(WindowsSocketsAPI没有提供发现MTU的机制,但是它不会小于512个字节)。
WinSock2.0版中已被废弃。
lpVendorInfo:
指向销售商的数据结构的指针。
这个结构的定义(如果有)超出了WindowsSockets规范的范围。
WinSock2.0版中已被废弃。
4设计过程
4.1新建对话框
启动VisualC++6.0,新建对话框应用程序,工程名为sanjin,对话框标题改为“主机名和IP地址”。
4.2添加控件
删除掉对话框模板上的控件,添加新控件,如下表所示。
表1控件及其属性一览表
控件
ID号
标题
属性
BUTTON
IDC_BUTTON1
擦除
默认
BUTTON
IDC_BUTTON2
退出
默认
StaticText
默认
—
Clientedge
CheckBox
IDC_CHECK1
运行
默认
添加完控件后的对话框模板如下图所示。
图1添加完控件后的对话框模板图
4.3添加成员变量
打开ClassWizard对话框的MemberVariables标签,为下列控件添加成员变量。
如下表所示。
表2控件及变量属性
控件ID
变量名
变量类型
数值范围
IDC_CHECK1
m_Chk1
BOOL
—
4.4为控件添加映射消息
选择MFCClassWizard对话框的MessageMaps标签,为以下控件添加映射消息。
如下表所示。
表3控件映射消息
Classname
Objectids
Messages
Memberfunctions
CSanjinDlg
IDC_BUTTON1
BN_CLICKED
On_Button1
CSanjinDlg
IDC_BUTTON2
BN_CLICKED
On_Button2
CSanjinDlg
IDC_CHECK1
BN_CLICKED
On_Check1
4.5定义函数
在sanjinDlg.h中定义一个Draw函数。
public:
voidDraw();
4.6添加代码
在sanjinDlg.cpp文件中添加代码,实现功能。
添加程序代码如下:
voidCSanjinDlg:
:
OnButton1()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
Invalidate();
}
voidCSanjinDlg:
:
OnButton2()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
OnOK();
}
voidCSanjinDlg:
:
OnCheck1()
{
//TODO:
Addyourcontrolnotificationhandlercodehere
m_Chk1=!
m_Chk1;//初始化
Draw();
}
voidCSanjinDlg:
:
Draw()
{
CClientDCdc(this);
intheight;
CFontfont;
height=75;
if(m_Chk1)
font.CreateFont(20,10,0,0,FW_NORMAL,false,false,false,
GB2312_CHARSET,OUT_DEVICE_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH,"宋体");
else
font.CreateFont(20,10,0,0,FW_NORMAL,false,false,false,
GB2312_CHARSET,OUT_DEVICE_PRECIS,
CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,
DEFAULT_PITCH,"楷体");
CRectrect(15,25,336,276);
dc.FillSolidRect(&rect,RGB(215,210,206));
dc.SelectObject(&font);
dc.SetBkMode(TRANSPARENT);
//初始化:
如果不初始化,以下代码将无法执行
WSADatadata;
if(WSAStartup(MAKEWORD(1,1),&data)!
=0)
{
dc.TextOut(25,45,"初始化错误,无法获取主机信息...");
}
charhost[255];
//获取主机名
if(gethostname(host,sizeof(host))==SOCKET_ERROR)
{
dc.TextOut(25,45,"无法获取主机名");
}
else
{
dc.TextOut(25,45,"本机主机名为:
");
dc.TextOut(75,75,host);
}
//获取计算机IP:
gethostbyname也需要初始化(上面已初始化)
structhostent*p=gethostbyname(host);
if(p==0)
{
dc.TextOut(25,45,"无法获取计算机主机名及IP...");
}
else
{
//本机IP:
利用循环,输出本机所有IP
for(inti=0;p->h_addr_list[i]!
=0;i++)
{
structin_addrin;
memcpy(&in,p->h_addr_list[i],sizeof(structin_addr));
dc.TextOut(25,height+(i+1)*height/3,"块网卡IP为:
");//除以3只能正常
//显示两个IP,要想显示多个IP地址还需添加一个计算IP地址个数的循环
dc.TextOut(75,height+(i+1)*height*2/3,inet_ntoa(in));
}
}
WSACleanup();
}
程序说明:
函数OnButton1()调用Invalidate()实现擦除功能,函数OnButton1()调用OnOK()实现退出功能,OnCheck1()作为触发主要功能程序Draw()运行的函数。
Draw()函数定义了一个CClientDC类的对象dc,和一个Cfont类的对象font。
定义对象dc来实现将所获得的主机名和IP地址显示在对话框上,定义对象font来设置字体样式。
4.7设计icon并运行程序
在ResourceView中擦除原icon,为自己设计一个Icon。
然后将程序编译并链接,运行程序,查看运行结果。
5程序运行结果及分析
程序运行的最终效果如图所示。
图2最终效果图
点击运行后,调用Draw()函数,Draw()函数调用gethostname()和getbyhostname()得到本地主机名和IP地址,并调用TextOut()显示在窗口的指定位置。
6心得体会
本次课设实现了获取本地主机名和IP地址的功能,并用基本对话框显示所获得的结果,可以说是成功的。
有一个小缺点是要使程序显示出主机名和IP地址是通过点击复选框,这不符合通常我们都是点击按钮的习惯。
但总体上我以为是成功的。
为了做这个课设,我确实花了一番心思。
虽说有C语言的基础,但实际上从我拿到题目查资料到最终做出来,我有一种从零学起的感觉。
这主要是因为VC++内容太多,一时之间难以接受这么多。
当然,这也从另一方面反映了VC++功能之强大,对这一点还从我查资料的过程中有所体会。
这次课设最大的收获可以说是更进一步了解了什么是学习,最大的进步是学会了如何面对问题。
以前遇到问题,我通常都会变得心浮气躁,甚至会想“罢工”,但这一次却没有。
这一次的课设过程还是我的一个新认识的落实。
说实话,我是这学期才明白“钻研”是什么意思,我觉得所谓“钻研”其实和“死磕”很有点像,只不过“钻研”需要心平气和,因为不心平气和就不容易长久。
我觉得我这次的课设就有点在和VC++“死磕”的感觉。
参考文献
[1]管皓,高永丽.别样诠释—一个VisualC++老鸟10年学习与开发心得.北京:
北京航空航天大学出版社,2012.11
[2]梁海英.VisualC++程序设计.北京:
清华大学出版社,2013
[3]唐文超.VisualC++网络编程.北京:
清华大学出版社,2013
[4]赵永发,刘莉莉.VisualC++入门经典.北京:
机械工业出版社,2013
[5]张水波,董志鹏.VisualC++网络大讲堂.北京:
清华大学出版社,2013
附录1sanjinDlg.cpp程序
//sanjinDlg.cpp:
implementationfile
//
#include"stdafx.h"
#include"sanjin.h"
#include"sanjinDlg.h"
#ifdef_DEBUG
#definenewDEBUG_NEW
#undefTHIS_FILE
staticcharTHIS_FILE[]=__FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
//CSanjinDlgdialog
CSanjinDlg:
:
CSanjinDlg(CWnd*pParent/*=NULL*/)
:
CDialog(CSanjinDlg:
:
IDD,pParent)
{
//{{AFX_DATA_INIT(CSanjinDlg)
m_Chk1=FALSE;
//}}AFX_DATA_INIT
//NotethatLoadIcondoesnotrequireasubsequentDestroyIconinWin32
m_hIcon=AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
voidCSanjinDlg:
:
DoDataExchange(CDataExchange*pDX)
{
CDialog:
:
DoDataExchange(pDX);
//{{AFX_DATA_MAP(CSanjinDlg)
DDX_Check(pDX,IDC_CHECK1,m_Chk1);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CSanjinDlg,CDialog)
//{{AFX_MSG_MAP(CSanjinDlg)
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
//添加消息响应函数,为每个消息处理函数加入一个入口
ON_BN_CLICKED(IDC_BUTTON1,OnButton1)
ON_BN_CLICKED(IDC_BUTTON2,OnButton2)
ON_BN_CLICKED(IDC_CHECK1,OnCheck1)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
//CSanjinDlgmessagehandlers
BOOLCSanjinDlg:
:
OnInitDialog()
{
CDialog:
:
OnInitDialog();
//Settheiconforthisdialog.Theframeworkdoesthisautomatically
//whentheapplication'smainwindowisnotadialog
SetIcon(m_hIcon,TRUE);//Setbigicon
SetIcon(m_hIcon,FALSE);//Setsmallicon
//TODO:
Addextrainitializationhere
returnTRUE;//returnTRUEunlessyousetthefocustoacontrol
}
//Ifyouaddaminimizebuttontoyourdialog,youwillneedthecodebelow
//todrawtheicon.ForMFCapplicationsusingthedocument/viewmodel,
//thisisautomaticallydoneforyoubytheframework.
voidCSanjinDlg:
:
OnPaint()
{
if(IsIconic())
{
CPaintDCdc(this);//devicecontextforpainting
SendMessage(WM_ICONERASEBKGND,(WPARAM)dc.GetSafeHdc(),0);
//Centericoninclientrectangle
intcxIcon=GetSystemMetrics(SM_CXICON);
intcyIcon=GetSystemMetrics(SM_CYICON);
CRectrect;
GetClientRect(&rect);
intx=(rect.Width()-cxIcon+1)/2;
inty=(rect.Height()-cyIcon+1)/2;
//Drawtheicon
dc.DrawIcon(x,y,m_hIcon);
}
else
{
CDialog:
:
OnPaint();
}
}
//Thesystemcallsthistoobtainthecursortodisplaywhiletheuserdrags
//theminimizedwindow.
HCURSORCSanjinDlg:
:
OnQueryDragIcon()
{
return(HCURSOR)m_hIcon;
}
voidCSanjinDlg:
:
OnButton1()
{
//TODO:
Addyourcontrolnotificationhandlercode