首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > 编程 >

java NIO非堵塞方式的Socket编程

2013-04-21 
java NIO非阻塞方式的Socket编程 .import java.net.*import java.nio.channels.*import java.util.*imp

java NIO非阻塞方式的Socket编程 .
import java.net.*;import java.nio.channels.*;import java.util.*;import java.io.*;public class NIOSocket{private static final int CLINET_PORT = 10200;private static final int SEVER_PORT = 10201;//面向流的连接套接字的可选择通道private SocketChannel ch;//通道选择器private Selector sel;public static void main(String[] args) throws IOException{//打开套接字通道ch = SocketChannel.open();//打开一个选择器sel = Selector.open();try{//获取与套接字通道关联的套接字,并将该套接字绑定到本机指定端口ch.socket().bind(new InetSocketAddress(CLINET_PORT));//调整此通道为非阻塞模式ch.configureBlocking(false);//为通道选择器注册通道,并指定操作的选择键集ch.register(sel, SelectionKey.OP_READ | SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT);//选择通道上注册的事件,其相应通道已为I/O操作准备就绪sel.select();//返回选择器的已选择键集Iterator it = sel.selectedKeys().iterator();while(it.hasNext()){//获取通道的选择器的键SelectionKey key = (SelectionKey)it.next();it.remove();//如果该通道已经准备好套接字连接if(key.isConnectable()){InetAddress addr = InetAddress.getLocalHost();System.out.println(“Connect will not block”);//调用此方法发起一个非阻塞的连接操作,如果立即建立连接,则此方法//返回true.否则返回false,且必须在以后使用finishConnect()完成连接操作//此处建立和服务端的Socket连接if(!ch.connect(new InetSocketAddress(addr, SEVER_PORT))){//完成非立即连接操作ch.finishConnect();}}//此通道已准备好进行读取if(key.isReadable()){System.out.println(“Read will not block”);}//此通道已准备好进行写入if(key.isWritable()){System.out.println(“Write will not block”);}}} finally{ch.close();sel.close();}}}

?

NIO Socket编程中有一个主要的类Selector,这个类似一个观察者,只要我们把需要探知的套接字通道socketchannel注册到Selector,程序不用阻塞等待,可以并行做别的事情,当有事件发生时,Selector会通知程序,传回一组SelectionKey,程序读取这些Key,就会获得注册过的socketchannel,然后,从这个Channel中读取和处理数据。

Selector内部原理实际是在做一个对所注册的channel的轮询访问,不断的轮询(目前就这一个算法),一旦轮询到一个channel有所注册的事情发生,比如数据来了,他就会站起来报告,交出一把钥匙,让我们通过这把钥匙来读取这个channel的内容。

2.使用NIO非阻塞方式Socket实现服务端和客户端程序:

通过下面一个简单的客户端/服务端程序说明一下NIO socket的基本API和步骤。

(1).服务端程序:

import java.net.*;import java.util.*;import java.io.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;public class NIOSocketServer{public static final int PORT = 8080;public static void main(String[] args)throws IOException{//NIO的通道channel中内容读取到字节缓冲区ByteBuffer时是字节方式存储的,//对于以字符方式读取和处理的数据必须要进行字符集编码和解码String encoding = System.getProperty(“file.encoding”);//加载字节编码集Charset cs = Charset.forName(encoding);//分配两个字节大小的字节缓冲区ByteBuffer buffer = ByteBuffer.allocate(16);SocketChannel ch = null;//打开服务端的套接字通道ServerSocketChannel ssc = ServerSocketChannel.open();//打开通道选择器Selector sel = Selector.open();try{//将服务端套接字通道连接方式调整为非阻塞模式ssc.configureBlocking(false);//将服务端套接字通道绑定到本机服务端端口ssc.socket().bind(new InetSocketAddress(PORT));//将服务端套接字通道OP_ACCEP事件注册到通道选择器上SelectionKey key = ssc.register(sel, SelectionKey.OP_ACCEPT);System.out.println(“Server on port:” + PORT);while(true){//通道选择器开始轮询通道事件sel.select();Iterator it = sel.selectedKeys().iterator();While(it.hasNext()){//获取通道选择器事件键SelectionKey skey = (SelectionKey)it.next();it.remove();//服务端套接字通道发送客户端连接事件,客户端套接字通道尚未连接if(skey.isAcceptable()){//获取服务端套接字通道上连接的客户端套接字通道ch = ssc.accept();System.out.println(“Accepted connection from:” + ch.socket());//将客户端套接字通过连接模式调整为非阻塞模式ch.configureBlocking(false);//将客户端套接字通道OP_READ事件注册到通道选择器上ch.register(sel, SelectionKey.OP_READ);}//客户端套接字通道已经连接else{//获取创建此通道选择器事件键的套接字通道ch = (SocketChannel)skey.channel();//将客户端套接字通道数据读取到字节缓冲区中ch.read(buffer);//使用字符集解码字节缓冲区数据CharBuffer cb = cs.decode((ByteBuffer)buffer.flip());String response = cb.toString();System.out.println(“Echoing:” + response) ;//重绕字节缓冲区,继续读取客户端套接字通道数据ch.write((ByteBuffer)buffer.rewind());if(response.indexOf(“END”) != -1) ch.close();buffer.clear();}}}}finally{if(ch != null) ch.close();ssc.close();sel.close();}}}

?

(2).客户端程序:

import java.net.*;import java.util.*;import java.io.*;import java.nio.*;import java.nio.channels.*;import java.nio.charset.*;public class NIOSocketClient{private static final int CLIENT_PORT = 10200;public static void main(String[] args) throws IOException{SocketChannel sc = SocketChannel.open();Selector sel = Selector.open();try{sc.configureBlocking(false);sc.socket.bind(new InetSocketAddress(CLIENT_PORT));sc.register(sel, SelectionKey.OP_READ | SelectionKey.OP_WRITE| SelectionKey.OP_CONNECT);int i = 0;boolean written = false;boolean done = false;String encoding = System.getProperty(“file.encoding”);Charset cs = Charset.forName(encoding);ByteBuffer buf = ByteBuffer.allocate(16);while(!done){sel.select();Iterator it = sel.selectedKeys().iterator();while(it.hasNext()){SelectionKey key = (SelectionKey)it.next();It.remove();//获取创建通道选择器事件键的套接字通道sc = (SocketChannel)key.channel();//当前通道选择器产生连接已经准备就绪事件,并且客户端套接字//通道尚未连接到服务端套接字通道if(key.isConnectable() && !sc.isConnected()){InetAddress addr = InetAddress.getByName(null);//客户端套接字通道向服务端套接字通道发起非阻塞连接boolean success = sc.connect(new InetSocketAddress(addr, NIOSocketServer.PORT));//如果客户端没有立即连接到服务端,则客户端完成非立即连接操作if(!success) sc.finishConnect();}//如果通道选择器产生读取操作已准备好事件,且已经向通道写入数据if(key.isReadable() && written){if(sc.read((ByteBuffer)buf.clear()) > 0){written = false;//从套接字通道中读取数据String response = cs.decode((ByteBuffer)buf.flip()).toString();System.out.println(response);if(response.indexOf(“END”) != -1) done = true;}}//如果通道选择器产生写入操作已准备好事件,并且尚未想通道写入数据if(key.isWritable() && !written){//向套接字通道中写入数据if(i < 10) sc.write(ByteBuffer.wrap(new String(“howdy ” + i + ‘\n’).getBytes()));else if(i == 10)sc.write(ByteBuffer.wrap(newString(“END”).getBytes()));written = true;i++;}}}}finally{sc.close();sel.close();}}}

?

热点排行