前几天编写一个App客户端,是一个长连接,我需要在app里开启一个服务,不断地接收服务器传来的消息,进行处理。我在Android Service里开启了一个线程,不断地轮询服务端传给我的消息。这时出现了一个问题,因为服务端大多时候不给我发消息,我肯定要在读服务器消息里的线程sleep一段时间在读。这时我问了我们领导,领导说用selector模式,不用等。
selector模式主要就是linux内核帮你监听端口,如果此端口有消息进来,马上就通知你,所以不用等。(不知道理解对不对,如果有误请指点,谢谢)。
下面上代码。
SocketChannel ch = null;
SocketAddress addr = new InetSocketAddress(172.16.3.194, 11904);
ch = SocketChannel.open(addr);
Selector selector=Selector.open();
ch.configureBlocking(false);
ch.register(selector, SelectionKey.OP_READ| SelectionKey.OP_CONNECT);
MyApplication.instance.selector=selector;
ApiSktChannel bfch = new ApiSktChannel(ch);
bfch.writeMsg(RssMap.toXml("login_req", new RssMap().push("userid", loginEntity.getUserName()).push("passwd", loginEntity.getMD5_PWD()), false));
MyApplication.instance.apiSktChannel=bfch;
MyApplication.instance.socketChannel=ch;
这些步骤主要是先创建一个Socket通道,然后把这个通道注册到Selector上,并把此通道和Selector保存到MyApplication中,方便service中直接获取。
注册时有四个参数 accept read write connect 我这里其实只关注读,所以我就注册了读。读的意思就是当有可读的消息,内核就会通知你去读。
在开始注册之前一定要先把socket设置成非阻塞模式,因为会在selector中阻塞。
下面只需要调用阻塞方法
selector.select()
此方法在没有发生你注册时的事件(accept write read connect)发生时,一直阻塞,但当有您注册的事件发生后就会执行下面的代码。所以我们只要在service中的while(true)中加上这行代码,就消除了延时。而且selector上可以注册多个socket通道哈。