不知道大家有没有“谈Socket色变”的经历?就像我一位朋友所说的,Socket这家伙啊,不得已而用之。哈,Socket真的那么恐怖吗?
其实这话一点也不假,Socket有时候真的不太好操控,也不好维护,但不管怎么样,我们还是要面对它的,没准Socket是一位大美女哦。
关于Socket的前世今生就不用我详述了,关于她的历史,已经不少人仁志士为她立传写著了,像我们国内的百度百科、互动百科等;全球著名的如维基百科之属。而且,能加入WP开发的学习行列的,我想各位对.NET的其它技术肯定是有一定基础的。我也相信,各位同仁过去一定也写过与Socket打交道的程序。那么,WP中的Socket又将如何呢?
前提公布答案吧,在WP中使用Socket跟你在其它桌面应用项目如WinForm,WPF等中是一样的,而且说白了,WP中的Socket只不过是从Silverlight框架中继承过来的。
.NET的一大优势就是集成性和统一性都好,这不,你看,无论你是编写桌面应用程序,还是WP上的应用程序,你会发现,你的学习成本不高,很多东西都是一样的,而且是相通的。显然这也是Win8和WP8的应用程序可以整合的原因吧。
在WP中使用Socket要注意以下几点:
1、WP客户端应用程序一般不被视为服务器端,因为不能进行绑定本地终结点和监听连接。但是,收发数据是没问题D。
2、在WP中的Socket操作(连接、接收以及发送)都是异步进行的。如果希望UI线程和后前线程进行同步,不妨使用System.Threading.ManualResetEvent类,这个东西不好讲述,也不好理解。这样吧,我举一个例子。
有一天,NC和脑残因为一件小事闹冲突,闹来闹去还是不能解决,怎么办呢?于是,NC和脑残决定来一场比试。两人约定以跑步方式比试,谁跑得快谁就是胜利者。然而,NC这个人一向比较自负,他相信脑残绝对跑不过他。这样,NC就修改了比赛规则:
NC让脑残先跑5秒,然后他才开始。
假设NC是主线程,脑残是后台线程,现在的情况是:主线程先等待一会儿,让后台线程先执行;后台线程执行5秒后向主线程发出信号,主线程收到信号后再继续往下执行。按照故事里的情节:NC先让脑残跑5秒钟,他自己就在起跑线上等待,脑残跑了5秒后向NC发出信号,NC看到信号后就开始跑。
下面介绍一个类——SocketAsyncEventArgs。
这个类作为启动异步操作时传递的参数,它可以包含如接收数据的缓冲区、远程主机、用户自定义对象等内容,这个类并不复杂,打开“对象浏览器”看看就一目了然了。
要设置用于异步接收数据的缓冲区,应调用SetBuffer方法。
好,理论就扯到这儿,其实也没有什么新的知识点,我只是简单提一下罢了。
按照惯例,大家都会猜到,理论过后要干什么了,是的,付诸实践。
在很多情况下,关于Socket的例子,都会做一个聊天程序的,不过,聊天程序要求服务器端和客户都具有发送和接收数据的功能,这样会增加实例的难度和代码长度,不方便入门者阅读。所以,想了一下,今天咱们不玩聊天的,今天咱们玩遥控飞机,如何?
程序代码较长,也不便于逐一来讲解,这样吧,为了保持代码的可读性,我会把完整的代码都贴出来,在代码中我会适当地加上注释。
先说一下原理,利用Socket进行通讯这不用说了,那是肯定的。功能是通过WP手机客户端应用程序来控制PC端播放、暂停和停止动画,而动画嘛,也不弄那么复杂了,就弄个矩形从左边移到右边的动画吧。
第一部分 服务器端
既然要播放动画,少不了要用WPF了,而且,也方便贴界面布局的代码。
1、新建WPF应用程序项目。
2、打开MainWindow.xaml文件(默认新建项目后自动打开),输入以下XAML代码。
3、打开MainWindow.xaml.cs文件,完成后台代码逻辑。
第二部分 WP客户端
1、新建Windows Phone应用程序项目。
2、打开MainPage.xaml文件,参考下面的XAML代码。
3、打开MainPage.xaml.cs,输入以下代码。
先运行服务器端,再在WP模拟器或真实手机上运行客户端。
在手机客户端中,输入IP地址,点“连接”,连接成功后,就可以发送指令了。
好的,就到这儿吧,示例的源码我会上专到“资源”中,有需要的话,大家可以按标题下载。
前面说过了,我第一门科班学习的编程语言就是Fortran77,其实我一直很奇怪为什么现在大家第一个程序都是hello world!可能是c语言的第一个程序是这个吧,反正我学Fortran77的时候第一个程序不是这个,第一次看的basic教程也不是hello world,QuickBasic教程的第一个程序也不是,不过后来再看一些语言的教程的时候都是hello world了,应该是跟c语言学的吧。
DOS下面的编程语言最熟练的是Fortran77,当然,仅限于当年,现在几乎都不会写了,还得看着书才会写了。basic是我DOS下面另一个写过程序的语言,而c语言我曾经把一本很厚的c语言教程看了一遍,但没真正写过什么程序。如果是数学计算的话,还是Fortran77好用,一是我比较熟练,二是本来Fortran就是为数值计算而生的,理论上应该速度比较快吧。与其它语言相比,最怀念的就是Fortran的复数运算,直接内置支持,工作中还是有很多时候用复数运行解决问题比较方便。后来都是用Point类型来当复数,然后自己写运算的函数,不过还是觉得没有直接支持复数的Fortran爽。
在windows下面用的第一个编程软件是VisualBasic4.0,装完后运行,面对着一个窗口不知道怎么办,在什么地方写代码?入口在哪里?能琢磨明白的就是可以在窗体上面拉一个按钮出来,但是怎么写代码就不知道了。当时也没有任何教程,唯一的资料就是VB自己带的帮助了。还好,当时VB4自带一个介绍的教程,按照教程知道了在什么地方写代码。当时给自己定了第一个目标,把窗体上的按钮上面的文本由button1改成ok,于是在窗体上画了一个按钮,然后在按钮的onclick事件中添加了设置button1的Caption的代码,试了两次,成功了。以后我再用新的可视化编程语言的时候,第一个程序都是更改按钮文本为ok。知道了在什么地方写代码,就可以写程序了,终于可以很容易的显示图片了,而且还很容易的就做出来windows的窗口,当时很是兴奋,可以完成我第一个比较像样的游戏了。我的第一个windows程序就是做了一个梭哈的游戏,当时一切都是全新的,除了基本的数值计算和逻辑判断外,其它的一切实现都是新的,从图片怎么显示隐藏,怎么显示提示一切都要一点一点去看帮助琢磨。当总体上做得差不多的时候,又有新的问题出现,因为当时我只会在按钮的事件中写代码,但是这就意味着程序运行后需要按一下开始按钮才能初始化所有数据,这有点太不专业了,应该直接启动后就初始化才对,当时在帮助中并没有找到程序入口main()的信息,倒是发现了窗体的Load事件,这里面写代码就可以在窗体出现后一切都初始化好了,在很长一段时间内,应该说在我用VB期间我都是把初始化信息放在这个事件中的。最后这个梭哈游戏做的还不错,同学在我的电脑上玩得还挺有兴趣。
VB4我只用了也就不到两周时间,因为很快我就有了VB5的光盘。用VB5编的第一个程序也是梭哈,完全从头开始编的,效果更好了一些。VB5给我印象最深的就是它的帮助,条理清晰,虽然没有查找功能,但是能够非常方便的找到想要的内容,还有最重要的一点,它是中文的。一两年后我看到过一些VB的书籍,我一看,这不就是VB的帮助直接复制粘贴过来的吗?在我用过的所有编程软件中,只有VB5的帮助我是完完整整地从头到尾看过至少两遍以上,那时候也没看什么教程,就是看帮助。这个习惯一直保持到现在,以后用VB6、Delphi、C#都是直接上手就写代码,不会的地方就去查帮助,等已经对这门语言有一定了解了之后才会去找本什么指南、教程之类的书来看看,对自己掌握的知识进行查缺补漏。
VB5与VB4区别很大,从VB5开始就不再支持VBX格式的控件了。当时买了很多关于VB编程资料、控件方面的光盘,里面有大量的VBX控件,可惜都不能用了。VB5其实用的时间也不能算太长,因为中国的计算机行业已经逐渐跟国际接轨了,很快VB6就出现了在我们的面前。对于我来说,VB5与VB6差距不算太大,反而不喜欢VB6的帮助。现在唯一能够很清楚记得的差别就是VB6有split函数,而VB5没有。虽然后来一直用VB6开发程序,但是由于VB6开发的程序需要msvbvm60.dll这个动态链接库,而windows98上面并没有带这个库。所以,我为了给别人程序不至于要人家也装这个库,通常都把VB6做的程序再用VB5重新生成一次,这样别人直接就能用了,也正是因为这个原因,我才发现VB5比VB6少一些函数。
VB5毕竟功能上差一些,所以后来为了在网上发布一些软件,就换成了Delphi,同时开始关注C#,Delphi用了五六年,开始一直使用C#。
我基本上是把自己定位为做普通桌面软件,所以C++基本上没怎么用过,用VC6做过一个测试程序,用BCB做过一个小软件,所以都不算数。需要底层一点的我一般用Delphi来做,虽然不如C调用系统API那么方便,但好歹我也都用Delphi实现了。
除了C#是为了跟上时代脚步才去学的外,其余的都是由于软件需求本身才选择的语言。不过自从用了C#后,觉得真是不错,唯一缺点就是框架本身太大,做小软件有点太夸张,通常还是用Delphi做,偶尔用C#。不过现在网络速度这么快,对于给能够直接联系到的好友做软件,一般还是用C#,反正下载一个.net框架也没多慢,而编些软件确实方便快捷很多了。
作者:陈曦
日期:2012-6-19 12:28:30
环境:[win7 Intel-based x64 vs2010]
转载请注明出处
Q: 在windows下,调用CreateProcess这个API来创建进程,它内部究竟做了什么?
A: 对于操作系统,一般肯定是分层的。内核将处理最终的创建进程操作,但是它的上层可能有一些模块,进行一些参数合法性判断或者为了可移植考虑的判断。windows同样不例外。看看windows下面内核上面的模块:
不妨先写一个CreateProcess的程序,通过逆向工程得到内部调用的东西。
Q: 如下代码:
编译成CreateProcessDemo.exe, 运行:
可以看出,它正确地创建了进程。
A: 下面我们将找出哪个模块包含CreateProcessA函数。进入VS的命令行工具,
使用如下命令dumpbin.exe /all CreateProcessDemo.exe > d:\dumpbin_createprocessdemo.txt得到所有dump的信息,找到如下信息:
可以看出,CreateProcessA是在KERNEL32.DLL中被引用的。
Q: 现在我们可以在kernel32.dll中查看CreateProcessA的调用关系了?
A: 是的。使用ida,打开系统目录下面的kernel32.dll, 并查找CreateProcessA函数的位置:
可以在靠近最后的时候发现调用CreateProcessInternalA例程。
Q: 继续查找CreateProcessInternalA例程的内部实现,它最终会调用CreateProcessInternalW来实现。继续查找CreateProcessInternalW的实现,发现它最终会调用NtCreateUserProcess例程(在xp下,会调用NtCreateProcessEx).此例程不在kernel32.dll中,它在哪里?
A: 正如上面的图示描述,它以nt开头,它在ntdll.dll中。同样适用ida打开ntdll.dll, 找到NtCreateUserProcess的实现:
Q: ZwCreateUserProcess是什么,好像和NtCreateUserProcess是一样的?
A: 仅仅在ntdll.dll中来说,依照上面的截图,它们是一致的;可是在内核中,它们不完全一致。Nt开头的例程会进行访问权限和参数合法性判断,而Zw不会,Zw它可以由内核模式代码直接使用;同时,调用Zw开头的例程会将先前的模式改变为内核模式,而使用Nt开头的例程不能。
Q: 刚刚所说的用户模式是如何进入内核模式的?
A: 上面的ntdll.dll中执行依然是用户模式,NtCreateUserProcess通过向eax传入中断号, edx传入7FFE0300H为参数地址来进行系统调用,进入内核模式。它的内部实现为:
因为未找到win7的WRK源代码信息,上面为nt内核的实现。
作者:陈曦
日期:2012-6-19 12:28:30
环境:[win7 Intel-based x64 vs2010]
转载请注明出处