最近闲的蛋疼,整了一下Java nio
传统的IO操作,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的
Java NIO非堵塞技术实际是采取Reactor模式,我们需要把socketchannel告诉Selector,我们接着做别的事情。当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据。
(Selector内部原理实际是在做一个对所注册的channel的轮询访问)。
下面是群聊的例子,以及nio之间传输对象,(别忘了序列化哦)
服务器端:
package socket.nioThreadSocket;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import socket.commonSocket.User;
public class Server implements Runnable{
private boolean running;
private Selector selector;
String writeMsg = "test";
private final int TimeOut=3000;
SelectionKey ssckey;
ExecutorService exec;
public Server(){
running=true;
/**启动线程池*/
exec=Executors.newCachedThreadPool();
}
public void init(){
try {
/*创建一个选择器*/
selector = Selector.open();
/*打开监听信道**/
ServerSocketChannel ssc = ServerSocketChannel.open();
/*设定非阻塞状态*/
ssc.configureBlocking(false);
/*绑定端口*/
ssc.socket().bind(new InetSocketAddress(2345));
// 将选择器绑定到监听信道,只有非阻塞信道才可以注册选择器.并在注册过程中指出该信道可以进行Accept操作
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){
// 等待某信道就绪(或超时)
if(selector.select(TimeOut)==0){
System.out.print("等待...");
continue;
}
if(selector.select() > 0){
System.out.println("running selector.selector() 方法...");
}
// 取得迭代器.selectedKeys()中包含了每个准备好某一I/O操作的信道的SelectionKey
Iterator<SelectionKey> it=selector.selectedKeys().iterator();
while(it.hasNext()){
SelectionKey key=it.next();
it.remove();
if(!key.isValid()) continue;
// 有客户端连接请求时
if(key.isAcceptable()){
getConn(key);
}
// 从客户端读取数据
else if(key.isReadable()){
readMsg(key);
}
else if(key.isValid()&&key.isWritable()){
if(writeMsg!=null){
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);
//sc.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
System.out.println("build connection :"+sc.socket().getRemoteSocketAddress());
}
private void readMsg(SelectionKey key) throws IOException {
StringBuffer sb=new StringBuffer();
SocketChannel sc=(SocketChannel)key.channel();
System.out.print(sc.socket().getRemoteSocketAddress()+" ");
ByteBuffer buffer=ByteBuffer.allocate(1024);
buffer.clear();
int len=0;
if(sc.read(buffer)>0){
ByteArrayInputStream input = new ByteArrayInputStream(buffer.array());
ObjectInputStream objInput = new ObjectInputStream(input);
try {
User user = (User)objInput.readObject();
System.out.println(user.getId()+"..........");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*写入对象*/
MyWriterObject o = new MyWriterObject("",sc);
exec.execute(o);
/*while((len=sc.read(buffer))>0){
buffer.flip();
sb.append(new String(buffer.array(),0,len));
}
if(sb.length()>0) System.out.println("get from client:"+sb.toString());
*/
/* if(sb.toString().trim().toLowerCase().equals("quit")){
sc.write(ByteBuffer.wrap("BYE".getBytes()));
key.cancel();
sc.close();
sc.socket().close();
}
else{
String toMsg=sc.socket().getRemoteSocketAddress()+ "said:"+sb.toString();
System.out.println(toMsg);
*/
/*Iterator<SelectionKey> it=key.selector().keys().iterator();
while(it.hasNext()){
SelectionKey skey=it.next();
if(skey!=key&&skey!=ssckey){
MyWriter myWriter=new MyWriter(skey,"");
exec.execute(myWriter);
}else{
//User user = new User();
//user.setId("001");
//key.attach(user);
服务器返回客户端对象形势
MyWriterObject o = new MyWriterObject(skey,"");
exec.execute(o);
}
else{
key.attach(writeMsg);
key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);
}
// }
//key.interestOps(SelectionKey.OP_READ);
}*/
}
public void run() {
init();
execute();
}
private void writeMsg(SelectionKey key) throws IOException {
System.out.println("++++enter write+++");
SocketChannel sc=(SocketChannel) key.channel();
String str=(String) key.attachment();
sc.write(ByteBuffer.wrap(str.getBytes()));
key.interestOps(SelectionKey.OP_READ);
}
}
class MyWriter implements Runnable{
SelectionKey key;
String msg;
public MyWriter(SelectionKey key,String msg){
this.key=key;
this.msg=msg;
}
public void run() {
try {
SocketChannel client = (SocketChannel) key.channel();
if(client == null|| !client.isConnected()||client.isConnectionPending()){
System.out.println("00000000000000000000000000000000000");
}
client.write(ByteBuffer.wrap(msg.getBytes()));
Thread.yield();
} catch (IOException ex) {
Logger.getLogger(MyWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
class MyWriterObject implements Runnable{
SelectionKey key;
String msg;
SocketChannel client;
public MyWriterObject(String msg,SocketChannel client){
this.client = client;
this.msg=msg;
}
public void run() {
try {
// SocketChannel client = (SocketChannel) key.channel();
User user = new User();
user.setId("001");
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bOut);
out.writeObject(user);
out.flush();
client.write(ByteBuffer.wrap(bOut.toByteArray()));
Thread.yield();
} catch (IOException ex) {
Logger.getLogger(MyWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
客户端:
package socket.nioThreadSocket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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 Client1 implements Runnable{
Selector selector;
boolean running;
SocketChannel sc;
public Client1(){
running=true;
}
public void init() {
try {
sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(new InetSocketAddress("localhost", 2345));
} catch (IOException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args){
Client1 client=new Client1();
new Thread(client).start();
}
public void execute(){
int num=0;
try {
while (!sc.finishConnect()) {
}
} catch (IOException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
}
ReadKeyBoard rkb=new ReadKeyBoard();
new Thread(rkb).start();
while(running){
try {
ByteBuffer buffer=ByteBuffer.allocate(1024);
buffer.clear();
StringBuffer sb=new StringBuffer();
Thread.sleep(500);
while((num=sc.read(buffer))>0){
sb.append(new String(buffer.array(),0,num));
buffer.clear();
}
if(sb.length()>0) System.out.println(sb.toString());
if(sb.toString().toLowerCase().trim().equals("bye")){
System.out.println("closed....");
sc.close();
sc.socket().close();
rkb.close();
running=false;
}
} catch (InterruptedException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void run() {
init();
execute();
}
class ReadKeyBoard implements Runnable{
boolean running2=true;
public ReadKeyBoard(){
}
public void close(){
running2=false;
}
public void run() {
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
while(running2){
try {
System.out.println("enter some commands:");
String str = reader.readLine();
System.out.println("get commands:"+str);
sc.write(ByteBuffer.wrap(str.getBytes()));
} catch (IOException ex) {
Logger.getLogger(ReadKeyBoard.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}
传统的IO操作,在打开一个I/O通道后,read()将一直等待在端口一边读取字节内容,如果没有内容进来,read()也是傻傻的等,这会影响我们程序继续做其他事情,那么改进做法就是开设线程,让线程去等待,但是这样做也是相当耗费资源的
Java NIO非堵塞技术实际是采取Reactor模式,我们需要把socketchannel告诉Selector,我们接着做别的事情。当有事件发生时,他会通知我们,传回一组SelectionKey,我们读取这些Key,就会获得我们刚刚注册过的socketchannel,然后,我们从这个Channel中读取数据。
(Selector内部原理实际是在做一个对所注册的channel的轮询访问)。
下面是群聊的例子,以及nio之间传输对象,(别忘了序列化哦)
服务器端:
package socket.nioThreadSocket;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
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.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import socket.commonSocket.User;
public class Server implements Runnable{
private boolean running;
private Selector selector;
String writeMsg = "test";
private final int TimeOut=3000;
SelectionKey ssckey;
ExecutorService exec;
public Server(){
running=true;
/**启动线程池*/
exec=Executors.newCachedThreadPool();
}
public void init(){
try {
/*创建一个选择器*/
selector = Selector.open();
/*打开监听信道**/
ServerSocketChannel ssc = ServerSocketChannel.open();
/*设定非阻塞状态*/
ssc.configureBlocking(false);
/*绑定端口*/
ssc.socket().bind(new InetSocketAddress(2345));
// 将选择器绑定到监听信道,只有非阻塞信道才可以注册选择器.并在注册过程中指出该信道可以进行Accept操作
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){
// 等待某信道就绪(或超时)
if(selector.select(TimeOut)==0){
System.out.print("等待...");
continue;
}
if(selector.select() > 0){
System.out.println("running selector.selector() 方法...");
}
// 取得迭代器.selectedKeys()中包含了每个准备好某一I/O操作的信道的SelectionKey
Iterator<SelectionKey> it=selector.selectedKeys().iterator();
while(it.hasNext()){
SelectionKey key=it.next();
it.remove();
if(!key.isValid()) continue;
// 有客户端连接请求时
if(key.isAcceptable()){
getConn(key);
}
// 从客户端读取数据
else if(key.isReadable()){
readMsg(key);
}
else if(key.isValid()&&key.isWritable()){
if(writeMsg!=null){
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);
//sc.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
System.out.println("build connection :"+sc.socket().getRemoteSocketAddress());
}
private void readMsg(SelectionKey key) throws IOException {
StringBuffer sb=new StringBuffer();
SocketChannel sc=(SocketChannel)key.channel();
System.out.print(sc.socket().getRemoteSocketAddress()+" ");
ByteBuffer buffer=ByteBuffer.allocate(1024);
buffer.clear();
int len=0;
if(sc.read(buffer)>0){
ByteArrayInputStream input = new ByteArrayInputStream(buffer.array());
ObjectInputStream objInput = new ObjectInputStream(input);
try {
User user = (User)objInput.readObject();
System.out.println(user.getId()+"..........");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/*写入对象*/
MyWriterObject o = new MyWriterObject("",sc);
exec.execute(o);
/*while((len=sc.read(buffer))>0){
buffer.flip();
sb.append(new String(buffer.array(),0,len));
}
if(sb.length()>0) System.out.println("get from client:"+sb.toString());
*/
/* if(sb.toString().trim().toLowerCase().equals("quit")){
sc.write(ByteBuffer.wrap("BYE".getBytes()));
key.cancel();
sc.close();
sc.socket().close();
}
else{
String toMsg=sc.socket().getRemoteSocketAddress()+ "said:"+sb.toString();
System.out.println(toMsg);
*/
/*Iterator<SelectionKey> it=key.selector().keys().iterator();
while(it.hasNext()){
SelectionKey skey=it.next();
if(skey!=key&&skey!=ssckey){
MyWriter myWriter=new MyWriter(skey,"");
exec.execute(myWriter);
}else{
//User user = new User();
//user.setId("001");
//key.attach(user);
服务器返回客户端对象形势
MyWriterObject o = new MyWriterObject(skey,"");
exec.execute(o);
}
else{
key.attach(writeMsg);
key.interestOps(SelectionKey.OP_READ|SelectionKey.OP_WRITE);
}
// }
//key.interestOps(SelectionKey.OP_READ);
}*/
}
public void run() {
init();
execute();
}
private void writeMsg(SelectionKey key) throws IOException {
System.out.println("++++enter write+++");
SocketChannel sc=(SocketChannel) key.channel();
String str=(String) key.attachment();
sc.write(ByteBuffer.wrap(str.getBytes()));
key.interestOps(SelectionKey.OP_READ);
}
}
class MyWriter implements Runnable{
SelectionKey key;
String msg;
public MyWriter(SelectionKey key,String msg){
this.key=key;
this.msg=msg;
}
public void run() {
try {
SocketChannel client = (SocketChannel) key.channel();
if(client == null|| !client.isConnected()||client.isConnectionPending()){
System.out.println("00000000000000000000000000000000000");
}
client.write(ByteBuffer.wrap(msg.getBytes()));
Thread.yield();
} catch (IOException ex) {
Logger.getLogger(MyWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
class MyWriterObject implements Runnable{
SelectionKey key;
String msg;
SocketChannel client;
public MyWriterObject(String msg,SocketChannel client){
this.client = client;
this.msg=msg;
}
public void run() {
try {
// SocketChannel client = (SocketChannel) key.channel();
User user = new User();
user.setId("001");
ByteArrayOutputStream bOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bOut);
out.writeObject(user);
out.flush();
client.write(ByteBuffer.wrap(bOut.toByteArray()));
Thread.yield();
} catch (IOException ex) {
Logger.getLogger(MyWriter.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
客户端:
package socket.nioThreadSocket;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
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 Client1 implements Runnable{
Selector selector;
boolean running;
SocketChannel sc;
public Client1(){
running=true;
}
public void init() {
try {
sc = SocketChannel.open();
sc.configureBlocking(false);
sc.connect(new InetSocketAddress("localhost", 2345));
} catch (IOException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args){
Client1 client=new Client1();
new Thread(client).start();
}
public void execute(){
int num=0;
try {
while (!sc.finishConnect()) {
}
} catch (IOException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
}
ReadKeyBoard rkb=new ReadKeyBoard();
new Thread(rkb).start();
while(running){
try {
ByteBuffer buffer=ByteBuffer.allocate(1024);
buffer.clear();
StringBuffer sb=new StringBuffer();
Thread.sleep(500);
while((num=sc.read(buffer))>0){
sb.append(new String(buffer.array(),0,num));
buffer.clear();
}
if(sb.length()>0) System.out.println(sb.toString());
if(sb.toString().toLowerCase().trim().equals("bye")){
System.out.println("closed....");
sc.close();
sc.socket().close();
rkb.close();
running=false;
}
} catch (InterruptedException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(Client1.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public void run() {
init();
execute();
}
class ReadKeyBoard implements Runnable{
boolean running2=true;
public ReadKeyBoard(){
}
public void close(){
running2=false;
}
public void run() {
BufferedReader reader=new BufferedReader(new InputStreamReader(System.in));
while(running2){
try {
System.out.println("enter some commands:");
String str = reader.readLine();
System.out.println("get commands:"+str);
sc.write(ByteBuffer.wrap(str.getBytes()));
} catch (IOException ex) {
Logger.getLogger(ReadKeyBoard.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
}