精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2011-03-24
最后修改:2011-04-26
用Socket和ServerSocket这两个类模拟监听80端口请求的WEB服务器 其实很简单的,我搞了一晚上才搞定。。。。。。 说说为神马吧,主要是InputStream的阻塞机制! 刚开始,我一次性读取1024字节,成功了。然后我又想到如果请求的字节数很长的话,只读取一次肯定不行, 于是就用循环的方法使用read方法读取Request输入流的数据。 然后,悲剧的事情就发生了!!! read方法竟然阻塞了,然后找资料找了好久找不到有用的资料, 只看见有人说用java.nio包里面的新类可以实现。 我就想啊,我是学习的,面对问题怎么能逃避了??? 于是继续研究其中的算法和InputStream提供的各种方法。(我想其中不合理的代码就不必贴了,认真看我这篇文章的人应该都能想到的) 最先啊,是看到java.nio.channel包里面有将InputStream转换为可读通道的方法,我就试了试,转换之后,发现、、、无论算法怎么处理、读取着还是不行啊。 仍然阻塞 然后,我想到一种方法: 就是定义字节数组一定长度LEN, 然后循环读取, 如果某一次读取到的数据(read(buf)的返回值)小于100的话,不是意味着输入流读取到了结尾了么? 然后我就高高兴兴的实现这种想法了 。 再然后呢。。。我就发现如果InputStream里面的字节数如果是LEN的整倍数的话,最后一次读取也是 ==LEN的,还是会出现read方法已经到了结尾但是循环仍然执行导致的阻塞现象 又一次失败了 我就继续想啊想,就想到了InputStream提供的available()方法,这个方法返回的是下一次读取的估计字节数,当初我就看到了这个方法,但是看到文档上说的这个方法不建议使用,就一直没想用。。。真是到了无可奈何啊。只好又试试这个方法的效果 于是呢,我就用了这种方法: 在每一次循环读取之前判断InputStream剩余的字节数是不是 0 、即剩余字节是不是空的,如果是空的就不读了,这种方法果然奏效!!! 但是经过我的反复测试啊,发现又出现了一个问题,同一个浏览器的同一个页面如果刷新的话,这个页面第一次请求时候available() 正常, 下来的请求就不正常了,available()直接就 == 0 了, 第一次页面请求之后的每一次页面刷新后台都读取不到请求数据。 Socket我都关闭了啊!怎么会出现这种情况??? 纳闷了, 又找了好长时间的资料,仍然没有解决办法。好像是上一次处理的InputStream的available()保留下来了一样,但是如果另开一个页面请求就正常。。。。 然后就是我想到的终极解决办法了, 我假设的是用户请求内容不可能是空值,于是,我就用了do{}while循环,先执行读取一次,在判断available()的值是不是0,这样就保证了上一个问题的影响。 至于为什么这么做,我也是说不明白的,就是当时的一种灵感吧。。。我感觉是为了把InputStream读取指针先放在流头。这样可以避免干扰。 额语文水平很低啊、看的同学们勉强凑合吧 小弟现在大二,经验有限,高手老鸟轻喷啊 第一次发不会贴代码、试试吧! 主服务类: package server.test01; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.InetAddress; import java.net.ServerSocket; import java.net.Socket; /** * @author sulin */ public class MyService { private final String HOST = "127.0.0.1"; //绑定的主机127.0.0.1,不设置也可、默认即为IP或localhost private final int BACKLOG = 1; //最大请求并发量 private final int PORT = 80; //服务器绑定端口 public void startService(){ //建立指定HOST和PORT的服务器 ServerSocket server = null; try { server = new ServerSocket(this.PORT, this.BACKLOG, InetAddress.getByName(this.HOST)); } catch (IOException e) { e.printStackTrace(); } //服务开始工作 System.out.println("服务器开始工作"); while(true){ try{ //侦测一次请求 final Socket socket = server.accept(); final InputStream in = socket.getInputStream(); final OutputStream out = socket.getOutputStream(); //多线程机制响应请求 new Thread(){ public void run() { try { //处理响应侦探到的请求 MyRequest request = new MyRequest(in); request.Parse(); MyResponse response = new MyResponse(out); response.setRequest(request); response.SendResponse(); //本次请求处理结束 socket.close(); } catch (IOException e) { e.printStackTrace(); } } }.start(); }catch(Exception e){ e.printStackTrace(); } } } /** * 程序入口 * @param args */ public static void main(String[] args) { MyService service = new MyService(); service.startService(); } } 请求处理类 package server.test01; import java.io.IOException; import java.io.InputStream; public class MyRequest { private InputStream in; //请求的输入流 private String uri; //请求的uri private String request = ""; //请求处理后的字符串 public MyRequest( InputStream in ) { this.in = in; } public String getUri() { return uri; } /** * 提供对request请求的解析服务 */ public void Parse(){ try { byte[] buffer = new byte[377]; int len; do{ len = in.read(buffer); request += new String(buffer).substring(0, len); }while(in.available()>0); } catch (IOException e) { e.printStackTrace(); } this.uri = this.ParseURI(); System.out.println(uri); } private String ParseURI(){ String[] ss = this.request.trim().split(" "); if(ss.length > 2){ return ss[1]; }else{ return ""; } } } 另外一个相应类MyResponse就不贴了。。。 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |
发表时间:2011-03-24
没人响应啊。 可能都老鸟,我这个帖子才菜鸟了吧
|
|
返回顶楼 | |
发表时间:2011-03-24
现在的大学生这么勤奋啊,我大二的时候都没写过代码,只会玩游戏!
|
|
返回顶楼 | |
发表时间:2011-03-24
1. Socket/ServerSocket 本来就是阻塞的,java.nio 才是非阻塞的。你非要将 A 搞成 B 的话,总有点差强人意。
2. 在网络流操作的时候,是不建议使用 available() 的。 |
|
返回顶楼 | |
发表时间:2011-03-25
avgguy 写道 1. Socket/ServerSocket 本来就是阻塞的,java.nio 才是非阻塞的。你非要将 A 搞成 B 的话,总有点差强人意。
2. 在网络流操作的时候,是不建议使用 available() 的。 为神马不建议使用available |
|
返回顶楼 | |
发表时间:2011-03-25
大二,你把学生证贴下?
|
|
返回顶楼 | |
发表时间:2011-03-25
好像不能运行~~~
|
|
返回顶楼 | |
发表时间:2011-03-25
fnasty 写道 现在的大学生这么勤奋啊,我大二的时候都没写过代码,只会玩游戏!
也很勤奋嘛,我大二的时候只会上网看个H图片.....那时候真好啊,没有great wall. |
|
返回顶楼 | |
发表时间:2011-03-29
sky_dream 写道 大二,你把学生证贴下?
真的啊、 河南大学大二的、去年暑假加入了学院的网络工程实验室学习j2ee |
|
返回顶楼 | |
发表时间:2011-03-29
avgguy 写道 1. Socket/ServerSocket 本来就是阻塞的,java.nio 才是非阻塞的。你非要将 A 搞成 B 的话,总有点差强人意。
2. 在网络流操作的时候,是不建议使用 available() 的。 但是如果不用nio里面的ServerSocketChannel的话,仍然有阻塞现象啊、 我试了好几次。。。 如果非得用ServerSocketChannel的话 还是费点事把ServerSocket实现了吧、学习呢不能偷懒 |
|
返回顶楼 | |