Java Nio 保持长连接分发消息

求助:Java Nio 保持长连接分发消息最近闲来无事想做个小型的聊天工具,客户端用android已经做好了,跟服务器

求助:Java Nio 保持长连接分发消息
最近闲来无事想做个小型的聊天工具,客户端用android已经做好了,跟服务器的交互不想使用Http的方式,改用socket长连接,这样的话消息能及时送达就避免了http不断轮询的消耗。
网上关于Java NIO大部分都是些基础的例子和结构,关于长连接的实在是很少,
现在已经能正常监听请求和读写内容,但是没办法让服务器发送消息到指定的一台或若干台客户端,老的JavaIO可以通过保存Socket,但是nio每次事件都是一个新的SelectionKey,保存了也是旧的(目前的理解),请教各位,如何才能保存下跟每个客户端的会话呢,如下是部分代码


public class SeekServer extends Thread{
private final int ACCPET_PORT = 55555;
private final int TIME_OUT = 3000;
private Selector mSelector = null;
private ServerSocketChannel mSocketChannel = null;
private ServerSocket mServerSocket = null;
private InetSocketAddress mAddress = null;

public SeekServer() {
long sign = System.currentTimeMillis();
try {
mSocketChannel = ServerSocketChannel.open();
if(mSocketChannel == null) {
System.out.println("can't open server socket channel");
}
mServerSocket = mSocketChannel.socket();
mAddress = new InetSocketAddress(ACCPET_PORT);
mServerSocket.bind(mAddress);
Log.i("server bind port is " + ACCPET_PORT);
mSelector = Selector.open();
mSocketChannel.configureBlocking(false);
SelectionKey key = mSocketChannel.register(mSelector, SelectionKey.OP_ACCEPT);
key.attach(new Acceptor());
Log.i("Seek server startup in " + (System.currentTimeMillis() - sign) + "ms!");
} catch (ClosedChannelException e) {
Log.e(e.getMessage());
} catch (IOException e) {
Log.e(e.getMessage());
} 
}

public void run() {
Log.i("server is listening...");
while(!Thread.interrupted()) {
try {
if(mSelector.select(TIME_OUT) > 0) {
Log.i("find a new selection key");
Set<SelectionKey> keys = mSelector.selectedKeys();
Iterator<SelectionKey> iterator = keys.iterator();
SelectionKey key = null;
while(iterator.hasNext()) {
key = iterator.next();
Runnable at = (Runnable) key.attachment();
if(at != null) {
at.run();
}
keys.clear();
}
}
} catch (IOException e) {
Log.e(e.getMessage());
}
}
}

class Acceptor implements Runnable{

public void run(){
try {
SocketChannel sc = mSocketChannel.accept();
new Handler(mSelector, sc);//开始处理这个Channel
} catch (ClosedChannelException e) {
Log.e(e);
} catch (IOException e) {
Log.e(e);
}
}
}
}

[最优解释]
楼主,其实可以不用socket,我们组一直用servlet 3.0的异步功能和android保持长连接的,只需要写一个监听类,然后在请求进来,处理完逻辑后如果不用返回,挂起即可,完全能满足你的需求.
[其他解释]
不懂 友情帮顶!
[其他解释]
友情帮顶~
[其他解释]
sokect 其实我也不懂,  过些天会看看
[其他解释]


肯定能吧,不是有NIO的聊天室吗?
[其他解释]
你不是已经拿到了SocketChannel吗,把准备需要发送给客户端的数据在这个上面注册一个写事件.


SocketChannel channel = (SocketChannel) key.channel();
channel.register(ioSelector, SelectionKey.OP_WRITE, "这是传回的数据.");


其中第三个参数就是你要转给客户端的数据封装,接着你只需要在写事件的响应方法中写输出逻辑就行了.这里简单用了字符串.


private void writeable(SelectionKey key) throws IOException {
        SocketChannel socketChannel = (SocketChannel) key.channel();
        byte[] data = ((String) key.attachment()).getByte("utf8);

        int len = 0;
        
        ByteBuffer buff = ByteBuffer.wrap(data,0,data.length);
        len = socketChannel.write(buff);

        if (len == EOF_FLAG) {
            //认为客户端已经被关闭了
            throw new ConnectException("close channel.");
        }

        //判断数据没有输出完的处理
    }


这里有一点要注意,因为是异步的IO所以数据不能保证一次write就能输出完.所以记录下已经输出的字节数,然后保存下
剩下的数据以便下一次写事件时输出.

最后数据完全输出完毕后建议将写事件从这个管道中去掉,不然一直有写就绪的事件浪费CPU.
key.interestOps(SelectionKey.OP_READ);
这句话就会接收读就绪事件了.
[其他解释]
引用:
快来人呀 这么多的分

不会又给一个人吧?
[其他解释]
可以考虑根据TCP协议的原理,用心跳包的方式连接确认。我们有个项目就是这样做的。
[其他解释]
两天不可能搞定 NIO 长连接的?
[其他解释]
引用:
引用:

两天不可能搞定 NIO 长连接的?


哈哈 那是当然,想做一个完善的东西,不可能抄几个网上的例子就搞定的,折腾快一个周了 有点眉目了


是应该定义一个全局的map存储链接标识以及对应的SocketChannel。
[其他解释]
NIO啊~~NIO 我写个非阻塞的通信就很郁闷啊~表示勉强看懂。
帮忙顶一下~~
[其他解释]
哈哈 赶上末班车
[其他解释]
快来人呀 这么多的分
[其他解释]
太郁闷鸟  折腾2,3天了
[其他解释]
再顶下
[其他解释]
引用:
你不是已经拿到了SocketChannel吗,把准备需要发送给客户端的数据在这个上面注册一个写事件.

Java code

SocketChannel channel = (SocketChannel) key.channel();
channel.register(ioSelector, SelectionKey.OP_WRITE, "这是传回的数据.");



其中第三个参数就……


比如有1-10个用户,我想把消息发送给2,3,4 我就得事先保存下SocketChannel,然后去这个集合里找2,3,4对应的SocketChannel,是不是切换读写事件就ok了呢?
------其他解决方案--------------------


引用:
可以考虑根据TCP协议的原理,用心跳包的方式连接确认。我们有个项目就是这样做的。


对 项目里下一步就会有心跳包,但首先我要把这些Channel存起来,然后去给这些Channel写数据,比较不理解的是每次都要切换read和write,不知道这样写会不会有什么问题
[其他解释]
我做过阻塞式socket的简单的聊天室,我用的是cookie保存客户端信息,不知道你能否借鉴。
[其他解释]
引用:
我做过阻塞式socket的简单的聊天室,我用的是cookie保存客户端信息,不知道你能否借鉴。


我也做过,但我在服务器端保存客户端会话,而且是nio
[其他解释]
引用:
两天不可能搞定 NIO 长连接的?


哈哈 那是当然,想做一个完善的东西,不可能抄几个网上的例子就搞定的,折腾快一个周了  有点眉目了
[其他解释]
引用:
引用:

你不是已经拿到了SocketChannel吗,把准备需要发送给客户端的数据在这个上面注册一个写事件.

Java code

SocketChannel channel = (SocketChannel) key.channel();
channel.register(ioSelector, SelectionKey.OP_WRITE, "这是……


你是需要对指定的SocketChannel发送数据,当然你保存的时候必须对这些SocketChannel进行标识。比如对每一个连接会产生一个唯一的ID,再利用一个Map来持有。

[其他解释]
上手弄nio的时候,就觉得太麻烦,太贴近底层,正好当时看到介绍mina的文章,觉得更能贴近业务,就直接用mina了。
[其他解释]
用apache的mina呀
[其他解释]
引用:
用apache的mina呀


连Mina底层的实现都不知道的话就直接去使用,感觉有点不充实
[其他解释]
引用:
引用:
引用:

两天不可能搞定 NIO 长连接的?


哈哈 那是当然,想做一个完善的东西,不可能抄几个网上的例子就搞定的,折腾快一个周了 有点眉目了


是应该定义一个全局的map存储链接标识以及对应的SocketChannel。

已经在尝试了,处理好之后把代码贴上来看看
[其他解释]
一直忘记来csdn了,把前段时间写的NIO雏形放到博客园了
传送门
[其他解释]
引用:
引用:

楼主,其实可以不用socket,我们组一直用servlet 3.0的异步功能和android保持长连接的,只需要写一个监听类,然后在请求进来,处理完逻辑后如果不用返回,挂起即可,完全能满足你的需求.


以前貌似听说过Tomcat7有这种功能哈,有相关的例子吗跪求

当然有,做过不止一个这样的项目了,不过我一直用的glassfish做服务器,tomcat支持的不是很好.你留个邮箱,或者QQ我晚上回家跟你讨论讨论.
[其他解释]
引用:
楼主,其实可以不用socket,我们组一直用servlet 3.0的异步功能和android保持长连接的,只需要写一个监听类,然后在请求进来,处理完逻辑后如果不用返回,挂起即可,完全能满足你的需求.


以前貌似听说过Tomcat7有这种功能哈,有相关的例子吗跪求
[其他解释]
NIO啊~~NIO 我写个非阻塞的通信就很郁闷啊~表示勉强看懂。
帮忙顶一下~~
[其他解释]
以前做个项目 加上心跳以后逻辑更乱 郁闷  nio不是一两天的功夫啊 = =
[其他解释]
package com.meran.nio.echoServer;

import java.io.IOException;
import java.nio.ByteBuffer; 
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ServerSocketChannel; 
import java.nio.channels.SocketChannel;


import java.nio.channels.Selector;
import java.nio.channels.SelectionKey;
import java.nio.channels.SelectableChannel;
import java.net.Socket;
import java.net.ServerSocket; 
import java.net.InetSocketAddress;
import java.util.Iterator;

public class Server {
public static final int PORT=8033;
   public static void main(String [] args) throws IOException{
   Server s=new Server();
   s.go();
   }
   private static ByteBuffer buff=ByteBuffer.allocateDirect(1024);
   
   public void go() throws IOException {
   ServerSocketChannel serverChannel=ServerSocketChannel.open();
   ServerSocket serverSocket=serverChannel.socket();
   serverSocket.bind(new InetSocketAddress(PORT));
   System.out.println("server start to listen port"+PORT);
   Selector selector =Selector.open();
   serverChannel.configureBlocking(false);
   serverChannel.register(selector, SelectionKey.OP_ACCEPT);
   while (true){
   int n=selector.select();
   if(n==0){
   continue;
   }
   else{
//   System.out.println(n+"complicated");
   Iterator it =selector.selectedKeys().iterator();
   while( it.hasNext()){
   SelectionKey key=(SelectionKey) it.next();
   if(key.isAcceptable()){

   ServerSocketChannel server = (ServerSocketChannel) key.channel();
   SocketChannel channel=server.accept();
   registerChannel(selector, channel, SelectionKey.OP_READ); 
   sayHello(channel);
   }
 if (key.isReadable()) 
   
 {
 
  readDataFromSocket(key); 
   
       }
   it.remove();
   
   }
   }
   }
   }
   
   

private void readDataFromSocket(SelectionKey key) throws IOException {
SocketChannel channel=(SocketChannel)key.channel();
int count =0;
buff.clear();
while((count=channel.read(buff))>0){
buff.flip();
while(buff.hasRemaining()){
channel.write(buff);
}

buff.clear();

}
if(count<0)
channel.close();


}

private void sayHello(SocketChannel channel) throws IOException {
buff.clear();
buff.put("hello\r\n".getBytes());
buff.flip();
channel.write(buff);

}

private void registerChannel(Selector selector, SocketChannel channel,
int opRead) throws IOException {
if(channel==null)
return;
channel.configureBlocking(false);
channel.register(selector, SelectionKey.OP_READ);



}

}
 获得 SocketChannel 直接 注册感兴趣的事件就是了


------其他解决方案--------------------


引用:
package com.meran.nio.echoServer;

import java.io.IOException;
import java.nio.ByteBuffer; 
import java.nio.channels.ClosedChannelException;
import java.nio.channels.ServerSocketChannel; 
impor……


哥们你太幽默了
[其他解释]
引用:
引用:
引用:

楼主,其实可以不用socket,我们组一直用servlet 3.0的异步功能和android保持长连接的,只需要写一个监听类,然后在请求进来,处理完逻辑后如果不用返回,挂起即可,完全能满足你的需求.


以前貌似听说过Tomcat7有这种功能哈,有相关的例子吗跪求

当然有,做过不止……

前段时间已经脱离JavaWeb了,现在搞Android 所以面向NIO的话合适点,留个邮箱以后方便交流
282910090@qq.com  公司不让用扣扣,你懂的
[其他解释]
引用:
引用:

引用:

引用:
引用:

楼主,其实可以不用socket,我们组一直用servlet 3.0的异步功能和android保持长连接的,只需要写一个监听类,然后在请求进来,处理完逻辑后如果不用返回,挂起即可,完全能满……


好的 谢谢,那就结贴了,来者有分
[其他解释]
引用:
引用:

package com.meran.nio.echoServer;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels……


哈哈 刚学两天 胡乱评论一下   
[其他解释]
引用:
引用:

引用:
引用:

楼主,其实可以不用socket,我们组一直用servlet 3.0的异步功能和android保持长连接的,只需要写一个监听类,然后在请求进来,处理完逻辑后如果不用返回,挂起即可,完全能满足你的需求.


以前貌似听说过Tomcat7有这种……


代码发给你了,请查收!
[其他解释]
来迟了,想来问下你的android客户端是怎样和java nio写的服务器端保持长连接的,采用socket吗?