socket获取数据 获取流超时

 

首先请查看一下JavaAPI,能够看到InputStream读取流有三个方法,分别为read(),read(byte[] b),read(byte[] b, int off, int len)。其中read()方法是一次读取一个字节,鬼都知道效率是很是低的。因此最好是使用后面两个方法。java

例如如下代码:程序员

Java代码  收藏代码编程

  1. /** 
  2.  * 读取流 
  3.  *  
  4.  * @param inStream 
  5.  * @return 字节数组 
  6.  * @throws Exception 
  7.  */  
  8. public static byte[] readStream(InputStream inStream) throws Exception {  
  9.     ByteArrayOutputStream outSteam = new ByteArrayOutputStream();  
  10.     byte[] buffer = new byte[1024];  
  11.     int len = -1;  
  12.     while ((len = inStream.read(buffer)) != -1) {  
  13.         outSteam.write(buffer, 0, len);  
  14.     }  
  15.     outSteam.close();  
  16.     inStream.close();  
  17.     return outSteam.toByteArray();  
  18. }  

 

咱们来测试一下:数组

Java代码  收藏代码网络

  1. public static void main(String[] args) {  
  2.     try {  
  3.         File file = new File("C:\\ceshi.txt");  
  4.         FileInputStream fin = new FileInputStream(file);  
  5.         byte[] filebt = readStream(fin);  
  6.         System.out.println(filebt.length);  
  7.     } catch (Exception e) {  
  8.         e.printStackTrace();  
  9.     }     
  10. }  

后台会打印这个文本的字节大小。看起来,这个是没有问题的。socket

 

 

关于InputStream类的available()方法
这个方法的意思是返回此输入流下一个方法调用能够不受阻塞地今后输入流读取(或跳过)的估计字节数。为何须要这个方法?由于在一些网络应用中,数据流并非一次性就能传递的,若是咱们仍是像上面那样去将这个流转换,会出问题的。咱们来作一个例子,这是一个Socket编程的简单例子,具体Socket内容我会在后面文章中解释的。工具

首先编写两个类,一个用户初始化Socket服务,而且处理每一个请求都有新的线程去处理,代码以下:测试

Java代码  收藏代码this

  1. package com.service;  
  2. import java.net.*;  
  3. public class DstService {  
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             // 启动监听端口 8001  
  7.             ServerSocket ss = new ServerSocket(8001);  
  8.             boolean bRunning = true;  
  9.             while (bRunning) {  
  10.                 // 接收请求  
  11.                 Socket s = ss.accept();  
  12.                 // 将请求指定一个线程去执行  
  13.                 new Thread(new DstServiceImpl(s)).start();  
  14.             }  
  15.         } catch (Exception e) {  
  16.             e.printStackTrace();  
  17.         }  
  18.     }  
  19. }  

那么处理类咱们也来看一下:.net

Java代码  收藏代码

  1. package com.service;  
  2. import java.io.*;  
  3. import java.net.*;  
  4. import com.util.*;  
  5. public class DstServiceImpl implements Runnable {  
  6.     Socket socket = null;  
  7.     public DstServiceImpl(Socket s) {  
  8.         this.socket = s;  
  9.     }  
  10.     public void run() {  
  11.         try {  
  12.             InputStream ips = socket.getInputStream();  
  13.             OutputStream ops = socket.getOutputStream();  
  14.             while (true) {  
  15.                 byte[] bt = StreamTool.readStream(ips);  
  16.                 String str = new String(bt);  
  17.                 System.out.println("主机收到信息:" + str);  
  18.                 String restr = "你好,主机已经收到信息!";  
  19.                 ops.write(restr.getBytes());  
  20.                 ops.flush();  
  21.             }  
  22.         } catch (Exception e) {  
  23.             e.printStackTrace();  
  24.         }  
  25.     }  
  26. }  

 至于工具类,我就直接给代码了:

Java代码  收藏代码

  1. package com.util;  
  2. import java.io.*;  
  3. public class StreamTool {     
  4.     public static void main(String[] args) {  
  5.         try {  
  6.             File file = new File("C:\\ceshi.txt");  
  7.             FileInputStream fin = new FileInputStream(file);  
  8.             byte[] filebt = readStream(fin);  
  9.             System.out.println(filebt.length);  
  10.         } catch (Exception e) {  
  11.             e.printStackTrace();  
  12.         }     
  13.     }     
  14.     /** 
  15.      * @功能 读取流 
  16.      * @param inStream 
  17.      * @return 字节数组 
  18.      * @throws Exception 
  19.      */  
  20.     public static byte[] readStream(InputStream inStream) throws Exception {  
  21.         ByteArrayOutputStream outSteam = new ByteArrayOutputStream();  
  22.         byte[] buffer = new byte[1024];  
  23.         int len = -1;  
  24.         while ((len = inStream.read(buffer)) != -1) {  
  25.             outSteam.write(buffer, 0, len);  
  26.         }  
  27.         outSteam.close();  
  28.         inStream.close();  
  29.         return outSteam.toByteArray();  
  30.     }  
  31. }  

 你能够直接运行这个类,会看到流被转换的效果。

咱们来写一个Socket客户端测试一下:

Java代码  收藏代码

  1. package com.client;  
  2. import java.io.*;  
  3. import java.net.*;  
  4. import com.util.*;  
  5. public class DstClient {  
  6.     public static void main(String[] args) {  
  7.         try {  
  8.             Socket socket = new Socket("127.0.0.1", 8001);  
  9.             // 开启保持活动状态的套接字  
  10.             socket.setKeepAlive(true);  
  11.             // 设置读取超时时间  
  12.             socket.setSoTimeout(30 * 1000);  
  13.             OutputStream ops = socket.getOutputStream();  
  14.             String mess = "你好,我是崔素强!";  
  15.             ops.write(mess.getBytes());  
  16.             InputStream ips = socket.getInputStream();  
  17.             byte[] rebyte = StreamTool.readStream(ips);  
  18.             String remess = new String(rebyte);  
  19.             System.out.println("收到主机消息:" + remess);  
  20.             socket.close();  
  21.         } catch (Exception e) {  
  22.             e.printStackTrace();  
  23.         }  
  24.     }  
  25. }  

 先运行DstService,而后运行客户端,看效果。会发现,控制台没有任何输出。通过调试发现,由于请求死在了

Java代码  收藏代码

  1. while ((len = inStream.read(buffer)) != -1) {  

这行代码上面。这就是在网络应用中会形成的后果。那么如何解决呢?有的人给出了以下代码:

Java代码  收藏代码

  1. int count = in.available();  
  2. byte[] b = new byte[count];  
  3. in.read(b);  

但是在进行网络操做时每每出错,由于你调用available()方法时,对发发送的数据可能尚未到达,你获得的count是0。须要作以下修改,是咱们的读取流方法改为以下:

Java代码  收藏代码

  1. /** 
  2.  * @功能 读取流 
  3.  * @param inStream 
  4.  * @return 字节数组 
  5.  * @throws Exception 
  6.  */  
  7. public static byte[] readStream(InputStream inStream) throws Exception {  
  8.     int count = 0;  
  9.     while (count == 0) {  
  10.         count = inStream.available();  
  11.     }  
  12.     byte[] b = new byte[count];  
  13.     inStream.read(b);  
  14.     return b;  
  15. }  

下面你在运行,会看到服务端和客户端都收到了消息。 

 

 

关于InputStream.read(byte[] b)和InputStream.read(byte[] b,int off,int len)这两个方法都是用来从流里读取多个字节的,有经验的程序员就会发现,这两个方法常常 读取不到本身想要读取的个数的字节。好比第一个方法,程序员每每但愿程序能读取到b.length个字节,而实际状况是,系统每每读取不了这么多。仔细阅读Java的API说明就发现了,这个方法 并不保证能读取这么多个字节,它只能保证最多读取这么多个字节(最少1个)。所以,若是要让程序读取count个字节,最好用如下代码:

Java代码  收藏代码

  1. int count = 100;  
  2. byte[] b = new byte[count];  
  3. int readCount = 0; // 已经成功读取的字节的个数  
  4. while (readCount < count) {  
  5.     readCount += inStream.read(b, readCount, count - readCount);  
  6. }  

 这样就能保证读取100个字节,除非中途遇到IO异常或者到了数据流的结尾状况!

相关文章
相关标签/搜索