版权声明:本文为博主原创文章,未经博主同意不得转载。 https://blog.csdn.net/zhuyijian135757/article/details/37672151
java Nio 通信与Bio通信主要不同点:
1.Nio中的单个channel就可以支持读操作也能够支持写操作,而bio中读操作要用inputstream,写操作要outputstream.
2.nio 採用byteBuffer 作为内存缓存区,向channel里写或者度操作,bio基本是用byte[]
3.nio採用 selector组件轮询读取就绪channel
服务端demo代码:
package com.my.socket3;
import java.io.ByteArrayOutputStream;
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.Iterator;
import java.util.Set;
import com.sun.xml.internal.messaging.saaj.util.ByteOutputStream;
public class ServerTest {
public static void main(String[] args) throws Exception {
server();
}
public static void server(){
ServerSocketChannel channel=null;
try{
Selector selector=Selector.open();
channel=ServerSocketChannel.open();
channel.configureBlocking(false);
channel.socket().setReuseAddress(true);
channel.bind(new InetSocketAddress(8020));
channel.register(selector, SelectionKey.OP_ACCEPT,new Integer(1));
while(true){
if(selector.select()>0){
Set<SelectionKey> sets=selector.selectedKeys();
Iterator<SelectionKey> keys=sets.iterator();
while(keys.hasNext()){
SelectionKey key=keys.next();
keys.remove();
if(key.isAcceptable()){
key.attach(new Integer(1));
SocketChannel schannel=((ServerSocketChannel) key.channel()).accept();
schannel.configureBlocking(false);
schannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
}
if(key.isReadable()){
SocketChannel schannel=(SocketChannel) key.channel();
ByteBuffer buf=ByteBuffer.allocate(1024);
ByteOutputStream output=new ByteOutputStream();
int len=0;
while((len=schannel.read(buf))!=0){
buf.flip();
byte by[]=new byte[buf.remaining()];
buf.get(by);
output.write(by);
buf.clear();
}
String str=new String(output.getBytes());
key.attach(str);
}
if(key.isWritable()){
Object object=key.attachment();
String attach=object!=null ? "server replay: "+object.toString() : "server replay: ";
SocketChannel schannel=(SocketChannel) key.channel();
schannel.write(ByteBuffer.wrap(attach.getBytes()));
}
}
}
}
}catch(Exception e){
e.printStackTrace();
}finally{
if(channel!=null){
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
客户端demo代码
package com.my.socket3;
import java.io.ByteArrayOutputStream;
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.SocketChannel;
import java.util.Iterator;
import java.util.Set;
public class ClientTest {
public static void main(String[] args) throws Exception {
client();
}
public static void client() {
SocketChannel channel=null;
try {
Selector selector=Selector.open();
channel = SocketChannel.open();
channel.configureBlocking(false);
channel.connect(new InetSocketAddress(8020));
channel.register(selector, SelectionKey.OP_CONNECT);
while(true){
if(selector.select()>0){
Iterator<SelectionKey> set=selector.selectedKeys().iterator();
while(set.hasNext()){
SelectionKey key=set.next();
set.remove();
SocketChannel ch=(SocketChannel) key.channel();
if(key.isConnectable()){
ch.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE,new Integer(1));
ch.finishConnect();
}
if(key.isReadable()){
key.attach(new Integer(1));
ByteArrayOutputStream output=new ByteArrayOutputStream();
ByteBuffer buffer=ByteBuffer.allocate(1024);
int len=0;
while((len=ch.read(buffer))!=0){
buffer.flip();
byte by[]=new byte[buffer.remaining()];
buffer.get(by);
output.write(by);
buffer.clear();
}
System.out.println(new String(output.toByteArray()));
output.close();
}
if(key.isWritable()){
key.attach(new Integer(1));
ch.write(ByteBuffer.wrap((("client say:hi")).getBytes()));
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}finally{
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class ClientRunnable implements Runnable{
private SocketChannel ch;
private ClientRunnable(SocketChannel ch){
this.ch=ch;
}
@Override
public void run() {
try {
while(true){
ch.write(ByteBuffer.wrap((("client say:hi")).getBytes()));
Thread.sleep(5000);
}
} catch (Exception e) {
e.printStackTrace();
try {
ch.close();
} catch (IOException e1) {
e1.printStackTrace();
}
}
}
}
}
跑demo时遇到的问题
1.客户端须要进行 ch.finishiCnonnect()操作,否则两边都堵塞着
2.读channel中的bytebuffer时, while((len=ch.read(buffer))!=0) 推断不要写成while((len=ch.read(buffer))!=-1)
假设SocketChannel被设置为非堵塞,则它的read操作可能返回三个值:
1) 大于0,表示读取到了字节数。
2) 等于0。没有读取到消息,可能TCP处于Keep-Alive状态,接收到的是TCP握手消息。
3) -1,连接已经被对方合法关闭。