我们先把前面的代码封装成一个完整的类,因为跟网络相关的方法并不一定是建立socket的服务器和客户端,所以还是应该把两个分开,比如获取本机IP,修改本机IP,PING远程主机这些事情应该放在一个单独的类里面,而且里面的方法应该是静态的(一个应用不会需要多个实例来做上面讲的这些事情),所以我个人建议做成一个单独的类FunctionNetwork,这样可以让主程序很简洁
?
注意可能涉及到IP地址自动获取和手动修改的方法,需要额外的DLL引用(System.Management),这部分功能暂时用不上
?
封装客户端的Socket类方法比较简单,大部分只要照抄前面的代码即可。但是在接收数据的时候我们使用了委托的方法对外传递数据。一般事件和委托成对使用比较方便(先不要管为什么这么写,照着抄就行了),delegate部分声明委托的名称和要传递数据的类型,event部分声明事件的名称。这个socket客户端的事件也就三种(连接成功,收到数据,断开连接,当然你也可以定义额外的事件,比如发送成功也算事件,发送失败也算事件)
?
当socket客户端已经OnRecieveMessageFromServerSuccess(收到的消息)发出去的时候,那么问题来了,谁来处理这个数据?我们当前的程序是需要主程序去处理,所以主程序在初始化的时候,只要声明当TheClient发生XXX事件的时候,就把他要传递的变量通过 +=的函数执行一次(注意用Tab自动补全,)然后就可以拿着这个类要传递的数据显示到控件上了。可以想象,如果不是Form1要用,而是其他的类或者窗体要用,也只要初始化的时候添加一条委托事件的绑定函数就可以了,确实非常方便(不然你怎么把某个类的某个方法产生的数据往外发?委托和事件就是为了解决这个问题来的)
?
还没有完,我们前面介绍的直接更新界面的数据,是通过关闭跨线程访问控件检测实现的,实际上这样做还不规范,实际上当主程序收到消息要更新控件之前,先判断XXX控件是否InvokeRequired,然后如果没有要执行Invoke方法,它里面的写法比较难看懂,也不需要理解,只要能照着葫芦画瓢就行了
?
与之对应的,另外两个委托的方法也是这样做(即便有多个控件要更新,也只需要考虑一个控件.InvokeRequired即可)
?
为了更清晰的看到从Server端发过来的数据,可以用字符串遍历出来(例如服务器发送一个字符A,其实除了这个字符还包括了回车换行 \r\n),可以看到我们定义的byte数组只有前面三位是有意义的(分别是65/13/10),查ASCII码表可以发现就是A+回车+换行(所以如果要解决中文乱码的问题,也需要响应的写转成byte和从byte提取,可能一个byte不足以表示一个中文,而大部分软件只认为传过来一个一个byte就是一个字符,所以强硬的把两个或者更多byte凑在一起才有意义的中文拆了导致的乱码)
?
当服务器断开连接的时候,实际上还是会发送一个空消息(当然你自己写服务器的或者客户端的时候也可以发送自定义消息),还是前面的方法可以测试出来,不管在服务器端点了StopListening直接停止服务器,还是Disconnect仅仅踢掉这个客户端,客户端都还能最后收到一笔byte数组,而这个数组里面啥也没有,这条消息就可以用来判断是不是服务器主动断开了连接
?
所以我们可以把软件做的比较完善,如果是服务器点击的断开连接,则提示服务器主动断开,如果是客户端点击的端口,则提示客户端要断开
?
而且不管是主动还是被动的断开连接,界面的按钮都要重置为连接可用,断开不可用,发送不可用(如果连接成功则相反),所以这也是用委托和事件的方式封装整个类的可能行为及触发的其他方法优势所在,如果不用事件和委托,这些事情也能做,但是要花费的代码和维护,修改的成本会大得多。
?
?
更多教学视频和资料下载,欢迎关注以下信息:
我的优酷空间:
http://i.youku.com/acetaohai123
?
我的在线论坛:
http://csrobot.gz01.bdysite.com/
?
问题交流:
QQ:910358960
邮箱:[email protected]
?
?
?