当前位置:首页 > 专题开发/技术/项目 > 网络通信

NIO服务主动推送信息有关问题

优良自学吧提供NIO服务主动推送信息有关问题,NIO服务主动推送信息问题今天在做基于NIO的推送服务器的时候,因为之前一直使用的IO,现在考虑更换用NIO的,在做Demo的时候发现了很多问题,捉摸了两天难以解决,而且网上的资料也不没有解答,上来问问各位大神们,我先把我的代码贴出来,如下: 服务器端: package com.defens.serve

NIO服务主动推送信息问题
今天在做基于NIO的推送服务器的时候,因为之前一直使用的IO,现在考虑更换用NIO的,在做Demo的时候发现了很多问题,捉摸了两天难以解决,而且网上的资料也不没有解答,上来问问各位大神们,我先把我的代码贴出来,如下:
服务器端:
package com.defens.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Date;
import java.util.Iterator;
import java.util.logging.Level;
import java.util.logging.Logger;

import com.defens.utils.ObjectToJson;

public class Server implements Runnable {

private boolean running;

private Selector selector;
private SelectionKey ssckey;

public Server() {
running = true;
}

/*
 * 服务器初始化函数
 */
public void init() {
try {
selector = Selector.open();
ServerSocketChannel ssc = ServerSocketChannel.open();
ssc.configureBlocking(false);// 非阻塞模式
ssc.socket().bind(new InetSocketAddress(2345));// 绑定端口
ssckey = ssc.register(selector, SelectionKey.OP_ACCEPT); // 注册
System.out.println("server is starting..." + new Date());
} catch (IOException ex) {
Logger.getLogger(Server.class.getName())
.log(Level.SEVERE, null, ex);
}
}

public static void main(String[] args) {
Server server = new Server();
new Thread(server).start();

}

/*
 * 执行函数
 */
public void execute() {
try {
while (running) {
int num = selector.select();
if (num > 0) {

Iterator<SelectionKey> it = selector.selectedKeys().iterator();
while (it.hasNext()) {
SelectionKey key = it.next();
it.remove();

System.out.println("key.isWritable:++++ " + key.isWritable());
System.out.println("key.isValid:++++ " + key.isValid());

if (!key.isValid()){
continue;
}
if (key.isAcceptable()) {
System.out.println("isAcceptable");
getConn(key);
} else if (key.isValid() && key.isWritable()) {
System.out.println("isWritable");
writeMsg(key);
} else {
break;
}
}
}
Thread.yield();// 把线程的状态有执行状态打回准备就绪状态
}
} catch (IOException ex) {
Logger.getLogger(Server.class.getName())
.log(Level.SEVERE, null, ex);
}
}

/*
 * 获取连接函数
 */
private void getConn(SelectionKey key) throws IOException {
ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
SocketChannel sc = ssc.accept();
sc.configureBlocking(false);
sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
key.interestOps(key.interestOps());
System.out.println("build connection :"+ sc.socket().getRemoteSocketAddress());
}

/*
 * 发送信息函数
 */
private void writeMsg(SelectionKey key) throws IOException {
System.out.println("++++enter write+++");
SocketChannel sc = (SocketChannel) key.channel();
String str = "hello World";
sc.write(ByteBuffer.wrap(str.getBytes()));
// 可保证返回的集合仅包含对于此键的通道而言有效的操作位。
// 可在任意时间调用此方法。是否受阻塞,以及阻塞时间长短都是与实现相关的。
key.interestOps(SelectionKey.OP_READ | SelectionKey.OP_WRITE); 
}

public void run() {
init();
execute();
}
}


客户端:
package com.defens.client;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Client implements Runnable {
private Selector selector;

boolean running;

private SocketChannel sc;

public Client() {
running = true;
}

public void init() {
try {
sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(new InetSocketAddress("localhost", 2345));

} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE,
null, ex);
}
}

public static void main(String[] args) {
Client client = new Client();
new Thread(client).start();
}

public void execute() {

try {
while (!sc.finishConnect()) {

}
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(Level.SEVERE,
null, ex);
}


        //该线程从socket中读取数据
while (running) {
this.receiveMessage();
}
}

private void receiveMessage(){
try {
int num = 0;
ByteBuffer buffer = ByteBuffer.allocate(1024);
buffer.clear();
StringBuffer sb = new StringBuffer();
while ((num = sc.read(buffer)) > 0) {
System.out.println("--------------");
sb.append(new String(buffer.array(), 0, num));
buffer.clear();
}
String receivedMessage = sb.toString();
System.out.println("++++++++" + receivedMessage);
} catch (IOException ex) {
Logger.getLogger(Client.class.getName()).log(
Level.SEVERE, null, ex);
}
}

public void run() {
init();
execute();
}
}


程序模拟的功能是,当客户端登录到服务器的时候,服务器推送发送一条信息到客户端,客户端输出在控制台上,但是程序在运行时的结果却是这样的,见下图:
服务器端:NIO服务主动推送信息有关问题
客户端:NIO服务主动推送信息有关问题
理论上应该是客户端连入到服务器端之后,只有一个连入了,服务只会发送一条,整个while循环只会进行一次,但是这里却是重复的发送,原先的selector.select();阻塞完全没有了,而且服务器只发送了一条信息,客户端却是有时能收到,有时又收不到,即使客户端的接受只进行一次客户端就关闭了,服务器端运行打印出的内容与上图中服务器效果完全一样,并且在客户端只有输出一条“++++++++”,却没有输出服务器发生的数据。求大神帮助,并对代码做适当的修改,感激不尽!
------解决思路----------------------
你的服务端的代码都注释掉了,不知哪部分是你用的。
if (key.isAcceptable()) 意思是当有客户端链接时,监听到的事件,假如你想当客户端链接进来就发送消息,就在这里调用你的writeMsg()方法。

选择器SelectionKey 还有read,wirte事件。意思是监听到有可读,写的事件时触发,比如你客户端发信息给服务器时,if (key.isRead())这时会触发,然后你就可以接受来在客户端的数据啦 

(本文来自互联网,不代表搜站(http://www.ylzx8.cn/)的观点和立场)
本站所有内容来自互联网,若本站收录的信息无意侵犯了贵司版权,请给我们来信(ylzx8cn@163.com),我们会及时处理和回复,谢谢