黑马程序员-Socket网络编程一点心得

------- android培训java培训、期待与您交流! ----------

之前在做一个手机与电脑通信的项目时,由于Java基础不牢,在Socket通信这一块, 碰到了不少麻烦,有些问题在网上查了好几天都找不到答案,只好自己动手解决,有些问题费了好大劲才解决,所以将问题与解决方法贴在这里,以供日后参考。(简要介绍一下这个项目:在电脑端启动服务器,然后通过手机发送指令到电脑端的服务器,服务器就能根据发送的指令对电脑做出一些基本的控制,例如定时关机、锁定计算机、从电脑下载文件到手机等等。该系统最好是工作在局域网内,否则会由于无法确定服务器IP地址而导致手机端无法正常工作。)

Socket对象在同一时间内只能返回一个字节输入流和一个字节输出流,若在前一个字节输入流(输出流)没有关闭

  的情况下,又使用getInputStream(getOutputStream)方法返回字节输入流(输出流),所返回的流的引用其实为空,
  此时若使用此流,将会产生空指针异常,导致程序出现异常.但是,从Socket对象返回的有效的字节输入流和输出流却可以
  同时作为多个过滤流类(例如 ObjectOutputStream类,InputStreamWriter类)实例化对象时的参数,这将不会引起
  程序的异常
  困扰了一下午之后的 重大发现!!!!ObjectInputStream和ObjectOutputStream在过滤流类里面是属于两个比较特
  殊的类.在建立Socket连接的时候,通讯的双方必须要首先创建一一对应的ObjectInputStream对象和
  ObjectOutputStream对象.甲方在创建ObjectOutputStream对象的时候,将自动向乙方发送一段序列化的头部,
  乙方在创建ObjectInputStream对象的时候,将会阻塞,直到接收到刚才甲方创建ObjectOutputStream对象时所发来的
  序列化头部为止,然后才继续向下执行.因此,若是有一方创建了ObjectInputStream对象,则另一方必须创建
  ObjectOutputStream对象.但是若一方创建了ObjectOutputStream对象,另一方却没有创建ObjectInputStream对象,
  这样是不会导致程序异常的,但是这样的ObjectOutputStream对象没有任何意义.
  有一点需要注意,当通信双方确定能创建相对应的两个对象时,还要确保ObjectInputStream对象接收到的消息一定守来自于
  另一方ObjectOutputStream对象发送的消息,否则的话不管ObjectInputStream对象是没有接收到消息还是接收到了
  错误的消息,都会导致创建ObjectInputStream对象发生阻塞,进而是程序失去响应.这就需要掌握好通讯双方的
  消息接收和发送顺序都能一一对应.
  如果这两个对象不是用于网络通信,而是用于本地文件的存储,则当ObjectOutputStream对象进行文件存储时,
  将会首先在文件的开头储存一段四字节的序列化头部,当ObjectInputStream对象在读取文件的时候,
  会首先读取这段四字节的文件头,如果发现序列号不正确,就会抛出StreamCorruptedException异常.
  今天下午在用本软件进行文件传输测试的时候,发现接收到的每个文件都多出了四个字节,接收到的文本文件,打开一看,
  在文件的开头,有一小块是乱码,这应该就是那多出来的四个字节.即使知道了这点,却怎么也找不出问题的所在,
  然后又修改服务器端的代码,结果发现,当把在构造函数里面实例化的ObjectOutputStream对象移到一个方法里去序列化时,
  手机终端在连接服务器的时候总是超时失去响应,非常纳闷,怎么一个ObjectOutputStream对象的实例化位置不同,还能引起
  这些意想不到的问题.没办法只好把服务器端的代码改回去,然后又研究手机终端的代码,看看这多出的四个字节到底是怎么来的.
  因为在下载文件的时候,发现每次都是只先接收四个字节,然后才开始接收到一波一波的大量的字节,于是就在正式接收文件的
  代码的前面加了一个read方法,将这四个字节首先读取出来并丢弃,然后才开始正式接收并存储接下来的字节,这样一来,
  所接收到的文件,就不再出现多处四个字节的现象了,接收到的文本文件在文件开头也不再出现一小块乱码的情况了.
  然后就把read方法往向代码的开头移动,把错误消灭在最开始,我是这样想的,而且我也以为这四个字节是建立
  网络连接的时候,通讯双方互相发送的"问候消息".没想到这样一改,启动手机终端的时候,程序又
  失去了响应,这真是太让人无语了.只好又把read方法往下移动,然后挨个试一下,看看从哪个地方出现问题,后来发现,只要把
  read方法移到ObjectInputStream对象实例化的前面,就会让程序失去失去响应,于是猜想可能是ObjectInputStream
  这个对象需要这四个字节,然后又去查看了一下Java文档对于ObjectInputStream的解释,(之所以又,是因为在开始
  修改服务器端代码导致程序程序失去响应的时候就曾怀疑过这两个类,查过文档,也注意到了下面文档的说法,但是
  仍然不能理解,也没找出答案).经过一下午的折腾,终于理解了下面文档的解释!!!!
  我在修改服务器端代码的时候,将ObjectOutputStream对象的实例化放在了方法里面,而在这个方法执行之前,就已经有一个
  read方法在等待接受来自手机终端的消息,而手机终端在启动以后,就立即实例化了一个ObjectInputStream对象,
  这个对象在等待来自服务器的ObjectOutputStream对象发来的消息,这样就导致了两方都在等待对方先发送消息,从而
  造成了程序失去响应.
  文档说: 创建从指定 InputStream 读取的 ObjectInputStream的对象。从流读取序列化头部并予以验证。
  在对应的 ObjectOutputStream 写入并刷新头部之前,此构造方法将阻塞。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值