BBYR Achieve
返回信息流
这是一条镜像帖。来源:北邮人论坛 / java / #17017同步于 2010/12/30
该镜像源已超过 30 天没有更新,可能在源站已被删除。
Java机器人发帖

请教NIO网络通信

salooloo
2010/12/30镜像同步2 回复
一个简单的nio通信例子: 服务器端: public class serv{ public static void main(String[] args){ Selector sel = null; ServerSocketChannel servChannal = null; CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); try { //打开通道 servChannal = ServerSocketChannel.open(); //绑定地址 servChannal.socket().bind(new InetSocketAddress(12345)); //设为非阻塞模式 servChannal.configureBlocking(false); //打开选择器 sel = Selector.open(); //通道指定要向哪个selector注册,通道所关注的事件是什么 servChannal.register(sel, SelectionKey.OP_ACCEPT); System.out.println("服务器开始接收客户的链接!"); while(true){ //阻塞并等待已注册的事件发生,有事件发生时立即返回 sel.select(); //当一个通道注册到选择器上时,选择器创建一个选择键与此通道相关联 //我们通过选择键来获取我们刚注册的通道 Iterator<SelectionKey> iterator = sel.selectedKeys().iterator(); while(iterator.hasNext()){ SelectionKey key = iterator.next(); //一个key被处理完成后,就都被从就绪关键字(ready keys)列表中除去 iterator.remove(); //测试此键的通道是否已准备好接收新的套接字连接 if(key.isAcceptable()){ //获取我们刚注册的通道 ServerSocketChannel ser2 = (ServerSocketChannel)key.channel(); SocketChannel channel = ser2.accept(); channel.configureBlocking(false); channel.register(sel, SelectionKey.OP_READ); System.out.println("客户端:" +channel.socket().getLocalAddress().getHostAddress()+":" +channel.socket().getPort()+"连接上了"); channel.write(encoder.encode(CharBuffer.wrap("你已连接到服务器!"))); } //测试此键的通道是否已准备好进行读取 else if(key.isReadable()){ SocketChannel channel = (SocketChannel)key.channel(); ByteBuffer buffer = ByteBuffer.allocate(50); try { channel.read(buffer); } catch (Exception e) { System.out.println("客户端:" + channel.socket().getInetAddress().getHostAddress() + ":" + channel.socket().getPort() + " 已断开连接"); channel.close(); continue; } //对该缓冲区作“翻回”操作,该方法将limit值置为当前位置,然后将当前位置指针position //置为0,并丢弃已定义的书签。 buffer.flip(); String msg = decoder.decode(buffer).toString(); System.out.println("收到消息来自:"+channel.socket().getLocalAddress().getHostAddress()+":" +channel.socket().getPort()+":"+msg); } } } } catch (IOException e) { e.printStackTrace(); }finally{ try { sel.close(); servChannal.close(); }catch (IOException e) { e.printStackTrace(); } } } } 客户端: public class client{ public static void main(String[] args){ clientThread clnt = new clientThread(); clnt.start(); InputStreamReader streamReader = new InputStreamReader(System.in); BufferedReader reader = new BufferedReader(streamReader); try { String readline; while((readline = reader.readLine()) != null){ if(readline.equalsIgnoreCase("bye")){ clnt.close(); System.exit(0); }else{ clnt.send(readline); } } } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public class clientThread extends Thread { private CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder(); private CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder(); private Selector sel = null; private SocketChannel socketChannel = null; private SelectionKey clntKey = null; public clientThread(){ try { sel = Selector.open(); socketChannel = SocketChannel.open(); socketChannel.configureBlocking(false); clntKey = socketChannel.register(sel, SelectionKey.OP_CONNECT); socketChannel.register(sel, SelectionKey.OP_CONNECT); InetSocketAddress ip = new InetSocketAddress(12345); socketChannel.connect(ip); } catch (ClosedChannelException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } public void run(){ try { while(true){ sel.select(); Iterator<SelectionKey> iterator = sel.selectedKeys().iterator(); while(iterator.hasNext()){ SelectionKey key = iterator.next(); iterator.remove(); if(key.isConnectable()){ SocketChannel channal = (SocketChannel)key.channel(); if(channal.isConnectionPending()){ channal.finishConnect(); } channal.register(sel, SelectionKey.OP_READ); System.out.println("连接服务器成功!"); } else if(key.isReadable()){ SocketChannel channel = (SocketChannel)key.channel(); ByteBuffer bbuf = ByteBuffer.allocate(50); channel.read(bbuf); bbuf.flip(); String msg = decoder.decode(bbuf).toString(); System.out.println("收到消息,来自:"+channel.socket().getLocalAddress().getHostAddress() + ":" + channel.socket().getPort() + ":" + msg); channel.write(encoder.encode(CharBuffer.wrap ("你好, 我是clnt1!"))); // channel.close(); } } } } catch (ClosedChannelException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); }finally{ try { sel.close(); socketChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } public void send(String msg){ try { SocketChannel channel = (SocketChannel)clntKey.channel(); channel.write(encoder.encode(CharBuffer.wrap(msg))); } catch (CharacterCodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void close(){ try { sel.close(); socketChannel.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 出现问题主要有两个: 1.客户端bye之后调用了socketChannel.close();然后server就在控制台一直输出: 收到消息来自:192.168.1.174:4685: 收到消息来自:192.168.1.174:4685: 收到消息来自:192.168.1.174:4685: 收到消息来自:192.168.1.174:4685: 请问server的sel.select();为什么能检测到了事件的发生?明明没有收到client的消息啊? 2.InputStreamReader streamReader = new InputStreamReader(System.in); BufferedReader reader = new BufferedReader(streamReader); readline = reader.readLine() 这里从控制台输入汉字“发送” 送字为乱码,如何解决这个问题? 恳请大牛指导
订阅后,新回复会通过你的通知中心匿名送达。
2 条回复
bobogogo机器人#1 · 2014/11/24
你可以试一下发送前的消息通过Charset.forName("UTF-8").newEncoder.encode(CharBuffer.wrap("发送")); UTF-8那里换成你自己的编码格式。
tiantiando机器人#2 · 2014/12/31
【 在 salooloo 的大作中提到: 】 : 一个简单的nio通信例子: : 服务器端: : public class serv{ : ................... 题外话,学习nio框架,比如netty