Section I Problem Specification
本次实验是用C/C++是在上一次实验:使用Arp协议获得本地局域网内在线主机MAC地址的基础上,进行一次的扩展。主要是做一个界面,并且因为要做界面多出了一个多线程的问题。出现多线程的原因是:必须有一个线程用于处理界面的事件。如此一说,反而像是我们在原来的基础上多做了一个线程,然后让这个线程去处理界面的事件,但实际情况不是这样。这是因为我在制作这种基于windows窗体程序的时候,基于了一个框架——MFC。这个框架可以理解为:微软专门为方便开发windows窗体程序的而设计的程序。在我以往的经验中,遇见了google专门为方便开发android应用而设计的程序,那时我管它叫sdk:Software Development Kit, 即软件开发工具包。
在这个框架下开发windows应用,无疑是非常方便的,但是我们也必须遵循这个框架已有的规矩:主线程就是控制界面的线程,这一点与我前面所说的多一个线程来控制界面相反。是在本来就有的界面线程的基础上,我创建了一个新的线程:来发包和收报在这次编写windows的程序过,我遇见了很多与开发android应用一样的准则。比如说:只要主线程才能更新界面,所以,当工作线程想要更新界面,也只有委托主线程。又比如:可以采用拖拉的方式来对界面进行布局,直观而又快速。
固,此次实验的重点是
1.制作界面。
2.多线程的应用。
3.与已有代码的融合。
Section II Solution Method and Design
对于界面的制作:
先利用MFC建立一个基于对话框的程序。当如此选择确定之后,MFC已经为我们生成了许多的内容。主要是对话框这个类以及初始化对话框的一些代码。此时,我们可以直接编译,会运行出现一个对话框。我们可以在资源视图内选择该对话框,再在工具箱内找到许多控件,这些控件包括:按钮,checkbox,listbox等等。我们可以直接拖动将其放置在对话框内。此时有4个要点:
1. 双击控件,可以直接调转到该控件的监听事件,比如:双击按钮控件就跳转到一个函数,当该按钮被点击时,该函数就会执行。我在android开发的时候,称为给button增加监听和响应函数。
2. 右键点击控件,在出来的弹窗内选择“添加变量”,这是指给这个控件命名。此外,该控件是属于对话框这个类的一个属性。我们也可以利用对话框的实例的引用调用它。
3. 右键点击控件,在出来的弹窗内选择“类向导”,我们可以在这里面添加额外的消息事件,比如双击按钮时响应的函数。这里面也比较统揽全局查看所有控件的所有能产生消息的事件。
4. Cdialog1Dlg::OnInitDialog()是当对话框刚产生的时候会执行的函数,可以将其作为这个程序的起点,一些初始化的内容可以写在里面。
对于多线程的制作
对我来说难度不大。也就是调用这个框架下的MFC而已,主要是以下几个函数:
1.创建一个线程
HANDLE m_hThread =CreateThread(NULL, 0, ThreadProcGetMacByWinpcap, this, 0, NULL);
其中重要的参数有:
ThreadProcGetMacByWinpcap:这是一个函数,就是线程开时候要执行的函数
This:this代表实例,由于我们有这个代码是写在对话框的这个类的实现函数里面,这个this就代表了目前我们这个对话框的实例(这个对象)。
2.暂停线程的运行:SuspendThread(m_hThread)
3.恢复线程的运行:ResumeThread(m_hThread)
4.停止线程: TerminateThread(m_hThread,0)
在适当的消息函数内使用上述几个api,就可以比较好的控制另一个线程。虽然控制线程的方法有很多,但是我在本试验中只用到了那么几个。本次实验,我也就只用到了2个线程。一个是主线程,一个就是发包和收包的线程。书上写的用了3个线程,我实在是看不出用三个线程的必要性。如下图所示:
关于与自己的代码融合:
我觉得也就是处理一堆逻辑,没有什么值得叙述的。本次实验本来应该难点,求出本网段所有在线主机的mac地址:处理方法也就是连续发253个就行了。
Section III Test Cases and Results Analysis
获取用户名非常耗时,所以分两种情况:
1. 不获得用户名,一般在1秒之内即可。
2. 获取用户名的,每次去获得一次用户名需要耗时4秒左右。
Section IV Conclusion
1.觉得iphelper用起来方便,所以用iphelper来获取了IP地址,子网掩码,本机mac地址,网关。发包和收包我还是用winpcap。
2.网关的mac地址使用了GetIpNetTable2的方法:http://msdn.microsoft.com/en-us/library/windows/desktop/aa814420(v=vs.85).aspx
3.我始终没有能够用winpcap拿到正确的ip。进而拿不到对子网掩码。这部分我打算打linux系统下验证,到底怎么回事
//sockaddr_in*sin=(sockaddr_in*)&(Dev->addresses->addr);
//MessageBox(inet_ntoa(sin->sin_addr));
4.关键是不能用iphelper的方法来拿到发arp。必须用winpcap来发。winpcap里面必须要选择一个打开的设备。这一步我又跳不过,但是最终还是找到了办法。因为pcap_open得第一参数需要dev的name,仔细观察这一部分,发现和用iphelper得到的pAdapter->AdapterName。后面的一段字符是一样的。 将这后面一段一样的比较一部分,就知道打开的是哪个设备了。
代码中的321行起。虽然有点二,但是我还是很找办法啦!!
5.由于用winpcap的方法不能获得在线主机的主机名字。需要调用gethostbyaddr的方法。但是这个方法非常花时间。所以我又添加了一个checkbox,以确定是否显示主机名字,如果不显示就会非常的快.为什么这么慢?
6.我们目前写个程序的流程。无非就是:
首先,明确自己要做什么,想要什么。
其次,怎么要,就是调哪个api。接着,就是 了解api的参数&#x