因为需要参考各种资料,所以还是需要一些时间才能够做好的。
而且在开发中,还会面对一些不得不仔细去解决的问题。
我打算尽量从Win32API的基础上面进行开发,能够不使用Delphi封装的类就不用,任何类都是无法避免多余的开销,而我们往往只使用一两个功能就付出那么大的代价,是否值得????
当然,别谈跨平台了,在中国,还是老老实实在Windows系统上面搞开发吧,而且服务器编程跟客户端没有直接的关系,客户端,你仍然可以采用任何语言进行开发,或者只使用JSocket的客户端控件就行。当然,如果时间允许,我们也可以自己封装一个,其实都差不多的,没有见得好到那里去。
客户端跟服务端不同,不需要关注并发连接的问题,也不用太在乎内存碎片的问题,反正玩家几个小时之后就会关机。常规情况下,那种病态的不用多说。
首先,我们不需要理会其它的逻辑处理等等事情,首务之急是构建我们的服务器内核。
要记住的是,我们采用的是非阻塞式的连接方式。
这些阻塞的意思是比如我给你打电话,我对你说:“嗨,回答我好吗??”这个时候,我在给你发送信息,接着我就站着等住你的回答,如果你一直都没有回答,那么好吧,我只能够傻站着等你的回话。直到你回答了为止,我才能够自由地活动。这种情况是不是很傻???
Delphi的控件面板也有IOCP完成端口的控件,只是它是阻塞式的。为了那个跨平台,呵呵。
非阻塞式的刚刚相反,我给你发信息,不管你回不回答,同样不影响我做其它事情。如果是投递函数,投递完毕后,立马返回。
好,我们去做一个我们自己能够控制的服务器控件。
为什么说是我们能够控制的呢,这个是我个人最喜欢做的事情,但是很累。
只有我们亲手去制作并且按照自己的想法去做的东西,我们才会清楚它的逻辑结构,并且在任何时候,出现任何问题,我们马上能够了解到那个地方出了问题,并且能够随时用最短的时间去修复它。
如果效率不理想,我们能够随时按照自己的理解来优化它。
这里我使用了随时这个词,当你面对着很多很多单元文件和很长很长的代码的时候,如果不是你自己亲手做的,谁能够保证,你能够如此爽快地随时啊??
不管我们做什么,都希望使用最短的时间做出最理想的东西来,对吧。
这个最理想是相对的,如果你有编程经验,应该不会对此有任何问题吧。
随着你编程水平的提高,很多以往的东西都会变得——弱智,但是我告诉你,这些不是弱智,相反,你现在所拥有的一切都是构建在这些弱智的曾经行为上面的。
有的人,认为:现在已经有很多库了,为什么我们还要继续制造轮子,而且不一定造得更好。
我的认为是:我们造的是自己的轮子,它比任何一切都实在和性能更高。
什么是最高性能和最高效率,我敢说,很多人都想不明白这个问题。
实际上,还是老话,只有你自己能够控制的东西才是最有效率的。
底层的东西,如果你认为这些才是最高效的,那么就得看看你对0和1的理解能力,看看你对CPU架构和微软的各种操作系统的最底层级别的了解了,如果还不够,你得对IDE编译器底层架构最深入的了解了,从硬件编码到系统的软编码,估计你要忙活一辈子,呵呵。
很多东西都是相对的,不要太难为自己。——也许是我自己在自我安慰吧,哈哈~就当是吧,我不介意就行。
原因很多,只要自己认为是这样就好。
也许大家都在认为我在废话多多,呵呵,是的,这个是我的“毛病”,大家将就吧。
OK,开始了——
首先,我们通过IDE上面的菜单项目——选择,还是看我的视频录制,本来我打算做个视频,然后在视频里面,咱们一步一步地构建这个控件。
但是,我想了下,优酷打开视频的时候,会播放大量的广告。
可是我们辛苦的作品,却免费地成了人家赚钱的通道,我不喜欢这样。
我的东西可以免费的同时,不能够增加任何垃圾的广告进里面。
要么,广告费,咱们分成,呵呵,想得天真,对吧。
那么我们做一些视频转换,做成GiF图片文件,对于网页来说,文件太大了,会有些少影响网页的打开。
其实不是所有人都做过控件,那么我们采用很简单的做法,不需要做得太复杂。
一个包就行,当然后面,我会提供一个图标,控件嘛,总得有自己的图标的对吧。
为什么搞成控件,很多原因,方便构建程序的时候增加IDE操作的交互吧。等等等。。。
如果是老鸟,请无视哈,呵呵。因为我的习惯就是这样,简单直接。
至于控件注册部分,习惯上,我会放到另一个单元文件里面。
那么后面的图标文件等操作将在以后的Gif文件里面演示。
需要在父类里面声明几个事件类型,方便我们在测试的时候或者在使用的时候调用。
先声明一个同窗体界面交互的信息提示事件。
TServerInfoEvent = procedure (Sender: TObject; nMsg:String) of object;
这个事件主要是把控件运行的情况,反映出来,方便我们观察代码执行的情况。
然后我们需要在基类的私有区域声明一个私有的事件成员字段。
strict private {信息反馈事件} FOnMsgInfoEvent: TServerInfoEvent;
要注意——Strict这个修饰符,如果是从D7时期转过来的同志,要注意采用了这个修饰符,那么在同一个单元里面,是不能够调用这个区域的字段成员的。不像以前那样了。
跟着在公有区域,声明一个如下的属性:
public property OnMsgInfoEvent: TServerInfoEvent read FOnMsgInfoEvent write FOnMsgInfoEvent;
那么在以后我们把控件安装到IDE里面的时候,就会从属性编辑器的事件界面那里看到这个事件了。
(大家也许认为应该添加在published区域,实际是需要这样做的,但是我们将在子类里面公开这些需要公开的部分。
是的,我打算采用两个类来操作。不用担心,两个类,不会很麻烦的。
控件注册的类,其实要改为子类,但是现在大家姑且保留那些注册内容,还没有到这部分的操作。)
怎么使用它,跟你使用那些啥鼠标事件等等是一样的,不同的是,你应该查看——nMsg这个字符串变量反馈回来的字符信息,你可以打印到Memo控件里面显示出来。或者,你可以增加事件声明的字段,比如,增加一个枚举类型的变量,如果反馈回来的是某个值,跟着做相应的操作等等。
还是老话:按照你自己的想法去做。
以上,还需要一个事件调用函数。如下:
procedure MsgInfoEvent(Const nMsg:String;Const ErrorCode: Integer = -1);
这个调用函数带两个参数,那么后面的这个参数也是对应于事件声明的。我增加了报错检测码,你们可以自己根据需要自己添加。如果你们想随时改变这个检测码,然后使代码发生改变,可以像JScoket控件那样做,采用一个Var 的变量来操作。
TServerInfoEvent = procedure (Sender: TObject; nMsg:String; ErrorCode: Integer = -1) of object;
或者:——
TServerInfoEvent = procedure (Sender: TObject; nMsg:String; Var ErrorCode: Integer) of object;
当然后面,我们还需要添加其它的事件。一步一步来。
那么事件调用函数是如何执行的,看下面:
procedure TComponentIocpSock.MsgInfoEvent(const nMsg: String; const ErrorCode: Integer); begin FOnMsgInfoEvent(Self,nMsg,ErrorCode); end;
记住ErrorCode这个参数早就被处理成默认初始化,所以在调用MsgInfoEvent函数的时候,你可以输入参数,也可以忽略它。