浏览 1639 次
锁定老帖子 主题:编写HTTP代理中,上一些我的工具方法。
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2010-04-16
最后修改:2010-04-16
http://feixing2008.iteye.com/blog/569927 其中我没有使用HttpClient这个东西,我想更直接地透传数据。下边写了几个工具方法,引出内容。还有出遇到的一些问题。 public static byte[] getDataByInputStream(InputStream in) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); byte[] b = new byte[BUF_SIZE]; int len = 0; while ((len = in.read(b, 0, BUF_SIZE)) != -1) { baos.write(b, 0, len); } baos.flush(); byte[] bytes = baos.toByteArray(); return bytes; } 上边的方法是从流中取出所有数据,放在数组中。BUF_SIZE常量自已设定,意义为缓冲区的大小。 在以上的基础上加增多一个方法 public static String getStrByInputStream(InputStream in, String outEncode) throws IOException{ byte[] btyStr = getDataByInputStream(in); String str = new String(btyStr, outEncode); return str; } 这个方法主要是将响应的数据转成字符串。其中outEncode是字符器的编码。这里我要说一个问题 就是Content-Length这个头的主要含义是上边btye[]的长度,而不是String的length()的长度。 Content-Length反映了字节流的长度,这个受操作系统编码的影响。所以需要得到响应的编码形式。 继续再看看这个方法。 public static String getStrEveryLine(InputStream in, String encode) throws IOException { StringBuilder rs = new StringBuilder(); Scanner inScn = new Scanner(in); String buf = ""; while(inScn.hasNextLine()){ buf = inScn.nextLine(); if(buf.length() < 1){ rs.append("\r\n"); break; } rs.append(buf); rs.append("\r\n"); } return rs.toString(); 这个方法是是通过Scanner来处理流数据。本来使用getStrByInputStream这个方法好像已满足需求,其实非也,因为出现一个问题。 问题: 浏览器发出请求时,在完成请求头后关不会将socket关闭的,也就是说 in.read()是不会返回-1,只是线程会一直阻塞在那里。 再具体一点就是这样 GET / HTTP/1.0 Host: www.taobao.com User-Agent: Mozilla/5.0 (X11; U; Linux i686; zh-CN; rv:1.9.0.11) Gecko/2009060308 Ubuntu/9.04 (jaunty) Firefox/3.0.11 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: zh-cn,zh;q=0.5 Accept-Encoding: text/html Accept-Charset: gb2312,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Cookie: t=31d7b3ed1734e98759c7009c7cc5d492; cna=G2ZHBE1o0hUCATjEb3H2nl0g <---------这里有个空行,读完这个空行再读的话会阻塞。所以读到这个空间就要跳出,不要再read 在请求头遇到这个情况还算好,因为可以通过一个空行可以发现头已经结束。 PS:不过这里还有个问题,如果是POST的话,在这个空行后边还是会有参数请求,这个时间就需要处理。然而我还没有实现。 在响应接收也是存在这个情况,这个问题更麻烦,因为是在响应数据流中读完一个字节流后阻塞,一般服务器是不会马上关闭Socket的,因为它不知你什么时间关闭,一般是等到10秒后才关闭。天吖,这个很影响我代理的性能。 其中一个解决方法是得到响应头的中Content-Length,再一次说明,这个头的值指的是字节流大小, 不是字符串大小。有了这个大小便可以根据大小读数据,知道何时数据已经完整,而不需要等服务器来关闭连接。 然而有时服务器是不会传Content-Length这个值。我也没有什么好方法,给合我代理的功能,我直接将流指向真实客服端的输出流当中。 BufferedInputStream bufIn = new BufferedInputStream(in); ArrayList<Byte> bys = new ArrayList<Byte>(); BufferedOutputStream outBuf = new BufferedOutputStream(outToClient); int c = 0; int cCnt = 0; while(( c = bufIn.read()) != -1){ ++cCnt; byte bc = (byte)c; bys.add(bc); outBuf.write(c); if((cCnt % 256) == 0){ outBuf.flush(); } } outBuf.close(); 这代码比较笨拙,其实不用细看,只是说明直接输到真实的客户端的输出流中。这个效率大大提升。 其中还有一个地方是线程池,这个是我需要改进的另一块,继续关注HTTP协议的相关开发。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |