论坛首页 Java企业应用论坛

关于NIO中异步读写的实践讨论

浏览 11459 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2012-04-20   最后修改:2012-04-20
不要把channel跟response完全切断啊,切断了你怎么知道哪个response去哪个通道,
好比从一个文件里读三段码流,然后说发出去吧,那怎么知道这三段码流分别去哪个通道。
通道是伴随着IO线程的啊。启动读写线程的时候都必须带上对应的通道或者说能随时取到通道。采集器采集到三个accept连接请求,那就是三个通道,三个通道分别注册读写事件,然后读写采集器再采集到读写事件获取不同通道,再利用通道启动读写线程。
剩下的问题不就是上面说的一个通道处理各种不同请求的问题了,那是业务层面协议的事情了。

0 请登录后投票
   发表时间:2012-04-20  

楼主呀,给你推荐一本关于NIO的读物,好好读下,对你大有帮助。

0 请登录后投票
   发表时间:2012-04-20  
CshBBrain 写道

楼主呀,给你推荐一本关于NIO的读物,好好读下,对你大有帮助。

 

谢谢啦~~正是找不到合适的书

0 请登录后投票
   发表时间:2012-04-21   最后修改:2012-04-21
[quote="CshBBrain"]
小试了一下,你的思路是正确的,但是实现的方法还是有点问题。

    ResponseIdentifier ri = new ResponseIdentifier(ResponseIdentifier.ONE);
    selectionKey.attach(ri);
    client.register(selector, SelectionKey.OP_WRITE)


这样子在后面选择write 的时候从selectionKey里取出来的attachment是null,我查阅了一下你给的书,上面有这个介绍
说在注册以后原来的selectionKey会被重新生成,所以保存的附件就没有了,为了保存附件,应该用register的重载方法:
client.register(selector, SelectionKey.OP_WRITE, identifier);


这样就可以被保留下来了

0 请登录后投票
   发表时间:2012-04-21  
CshBBrain 写道
须等待 写道
CshBBrain 写道
如果你只关心无法区分接收数据的链接和发送数据的连接是否为同一个连接的话,这个问题应该好弄;创建连接的时候创建一个标识连接的对象,然后把这个对象通过 SelectionKey 的这个方法 attach(obj)附带在SelectionKey 中,发送数据时调用attch()方法就可以取到创建连接时所创建的标识连接的对象了。用NIO来写好一个非阻塞式的服务器所面临的问题远不止这个......


恩,我关心的是怎么把异步的技术用于实践,因为我的需求过程,打个比方

---------------isReadable---------
request 1
request 2
读取两个请求并且计算响应response 1, response 2
---------------isWriteable--------
按照读写异步,这时是另外一个线程了,那么这个线程要去取读线程(或者说可能是来自独立的计算线程的结果),然后再发送,那么取结果的时候就需要判断这个结果是1还是2

通过附加标示符是可以解决问题,请问有没有示例的代码呢

 

 

  1. if (selectionKey.isAcceptable()) {  
  2.             System.out.println("Ready to accecpt a request ------------2");  
  3.             // 返回为之创建此键的通道。  
  4.             server = (ServerSocketChannel) selectionKey.channel();  
  5.             // 接受到此通道套接字的连接。  
  6.             // 此方法返回的套接字通道(如果有)将处于阻塞模式。  
  7.             client = server.accept();  
  8.             // 配置为非阻塞  
  9.             client.configureBlocking(false);  
  10.             // 注册到selector,等待连接  
  11.             client.register(selector, SelectionKey.OP_READ);  
  12.     
  13.     YourClass yc = new YourClass();// 这个类中可以定义一个AtomicInteger变量来记录是客户端发送的第几次请求,假如叫questNo
  14.     selectionKey.attach(yc);
  15.         } else if (selectionKey.isReadable()) {  
  16.             // 返回为之创建此键的通道。  
  17.             client = (SocketChannel) selectionKey.channel();  
  18.             System.out.println("Ready to read ----------------3");  
  19.             // 将缓冲区清空以备下次读取  
  20.             receivebuffer.clear();  
  21.             // 读取服务器发送来的数据到缓冲区中  
  22.             count = client.read(receivebuffer);  
  23.             if (count > 0) {  
  24.                 receiveText = new String(receivebuffer.array(), 0, count);  
  25.                 System.out.println("服务器端接受客户端数据--:" + receiveText);  
  26.                 client.register(selector, SelectionKey.OP_WRITE);  
  27.             } 
  28.    
  29.            ((YourClass)selectionKey.attach()).getQuestNo().getAndIncrement();//生成请求序号数,将这个值附到请求内容上,在生成响应信息的时候附到响应信息上(这个你自己设计下就可以了)
  30.         } else if (selectionKey.isWritable()) {  
  31.    //从响应信息中获取请求序号数,做处理(这个你自己设计下就可以了)
  32.             // 将缓冲区清空以备下次写入  
  33.             sendbuffer.clear();  
  34.             // 返回为之创建此键的通道。  
  35.             client = (SocketChannel) selectionKey.channel();  
  36.             System.out.println("Ready to write data ---------------------4");  
  37.             sendText = "message from server--";  
  38.             // 向缓冲区中输入数据  
  39.             sendbuffer.put(sendText.getBytes());  
  40.             // 将缓冲区各标志复位,因为向里面put了数据标志被改变要想从中读取数据发向服务器,就要复位  
  41.             sendbuffer.flip();  
  42.             // 输出到通道  
  43.             client.write(sendbuffer);  
  44.             System.out.println("服务器端向客户端发送数据--:" + sendText);  
  45.             client.register(selector, SelectionKey.OP_READ);  
  46.         }

 

小试了一下,你的思路是正确的,但是实现的方法还是有点问题。

 

ResponseIdentifier ri = new ResponseIdentifier(ResponseIdentifier.ONE);
    selectionKey.attach(ri);
    client.register(selector, SelectionKey.OP_WRITE)
 

 

这样子在后面选择write 的时候从selectionKey里取出来的attachment是null,我查阅了一下你给的书,上面有这个介绍

说在注册以后原来的selectionKey会被重新生成,所以保存的附件就没有了,为了保存附件,应该用register的重载方法:

 

client.register(selector, SelectionKey.OP_WRITE, identifier);
 

 

 

这样就可以被保留下来了

 

0 请登录后投票
   发表时间:2012-04-26  
楼主可以借鉴mina框架,里面有一个session的概念很好的实现了你的问题
0 请登录后投票
   发表时间:2012-05-08  
别惹Java 写道
楼主可以借鉴mina框架,里面有一个session的概念很好的实现了你的问题


恩,谢谢,早听说了mina的大名
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics