转自:https://www.iteye.com/blog/mars914-1238353
在java中可以基于java.nio.channels中的Channel和Selector的相关类来实现TCP/IP+NIO方式的系统间通信。
用于系统间通信依靠SocketChannel和ServerSocketChannel,SocketChannel用于建立连接,监听事件及操作读写,ServerSocketChannel用于监听端口及监听连接事件,可通过Selector来获取是否有要处理的事件。
服务端java代码:
- package com.java.distributed.message.tcpip;
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.net.ServerSocket;
- 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.nio.charset.Charset;
- public class NIOServer {
- /**
- * @param args
- * @throws IOException
- */
- public static void main(String[] args) throws IOException {
- int port =7889;
- //打开选择器
- Selector selector=Selector.open();
- //打开服务器套接字通道
- ServerSocketChannel ssc=ServerSocketChannel.open();
- //检索与此通道关联的服务器套接字
- ServerSocket serverSocket=ssc.socket();
- //将 ServerSocket 绑定到特定地址(IP 地址和端口号)
- serverSocket.bind(new InetSocketAddress(port));
- System.out.println("server listen on port:"+port);
- //调整通道的阻塞模式
- ssc.configureBlocking(false);
- //向给定的选择器注册此通道,返回一个选择键。SelectionKey.OP_ACCEPT--用于套接字接受操作的操作集位
- ssc.register(selector, SelectionKey.OP_ACCEPT);
- while(true){
- //timeout:为正,则在等待某个通道准备就绪时最多阻塞 timeout 毫秒;如果为零,则无限期地阻塞;必须为非负数
- int nKeys=selector.select(1000);
- if(nKeys>0){
- for(SelectionKey key:selector.selectedKeys()){
- /*测试此键的通道是否已准备好接受新的套接字连接--
- * 如果此键的通道不支持套接字接受操作,则此方法始终返回 false
- * */
- if(key.isAcceptable()){
- ServerSocketChannel server=(ServerSocketChannel) key.channel();
- SocketChannel sc=server.accept();
- if(sc==null){
- continue;
- }
- sc.configureBlocking(false);
- sc.register(selector, SelectionKey.OP_READ);
- }else if(key.isReadable()){
- //分配一个新的字节缓冲区
- ByteBuffer buffer=ByteBuffer.allocate(1024);
- SocketChannel sc=(SocketChannel) key.channel();
- int readBytes=0;
- String message=null;
- try{
- int ret;
- try{
- while((ret=sc.read(buffer))>0){
- readBytes +=ret;
- }
- }catch(Exception e ){
- readBytes=0;
- //ignore
- }finally{
- //反转此缓冲区。首先对当前位置设置限制,然后将该位置设置为零
- buffer.flip();
- }
- if(readBytes>0){
- message=Charset.forName("UTF-8").decode(buffer).toString();
- buffer=null;
- }
- }finally{
- if(buffer!=null)
- buffer.clear();
- }
- if(readBytes>0){
- System.out.println("message from client:"+message);
- if("quit".equalsIgnoreCase(message.trim())){
- sc.close();
- selector.close();
- System.out.println("Server has been shutdown!");
- System.exit(0);
- }
- String outMessage="server response:"+message;
- sc.write(Charset.forName("UTF-8").encode(outMessage));
- }
- }
- }
- selector.selectedKeys().clear();
- }
- }
- }
- }
客户端java代码:
- package com.java.distributed.message.tcpip;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.net.InetSocketAddress;
- import java.net.SocketAddress;
- import java.nio.ByteBuffer;
- import java.nio.channels.SelectionKey;
- import java.nio.channels.Selector;
- import java.nio.channels.SocketChannel;
- import java.nio.charset.Charset;
- public class NIOClient {
- /**
- * @param args
- * @throws IOException
- */
- public static void main(String[] args) throws IOException {
- int port =7889;
- SocketChannel channel=SocketChannel.open();
- channel.configureBlocking(false);
- SocketAddress target=new InetSocketAddress("127.0.0.1",port);
- channel.connect(target);
- Selector selector=Selector.open();
- //用于套接字连接操作的操作集位
- channel.register(selector, SelectionKey.OP_CONNECT);
- BufferedReader systemIn=new BufferedReader(new InputStreamReader(System.in));
- while(true){
- if(channel.isConnected()){
- String command=systemIn.readLine();
- channel.write(Charset.forName("UTF-8").encode(command));
- if(command==null||"quit".equalsIgnoreCase(command.trim())){
- systemIn.close();
- channel.close();
- selector.close();
- System.out.println("Client quit !");
- System.exit(0);
- }
- }
- int nKeys=selector.select(1000);
- if(nKeys>0){
- for(SelectionKey key:selector.selectedKeys()){
- if(key.isConnectable()){
- SocketChannel sc=(SocketChannel) key.channel();
- sc.configureBlocking(false);
- sc.register(selector, SelectionKey.OP_READ);
- sc.finishConnect();
- }else if(key.isReadable()){
- ByteBuffer buffer=ByteBuffer.allocate(1024);
- SocketChannel sc=(SocketChannel) key.channel();
- int readBytes=0;
- try{
- int ret=0;
- try{
- while((ret=sc.read(buffer))>0){
- readBytes+=ret;
- }
- }finally{
- buffer.flip();
- }
- if (readBytes > 0) {
- System.out.println(Charset.forName("UTF-8")
- .decode(buffer).toString());
- buffer = null;
- }
- }finally {
- if (buffer != null) {
- buffer.clear();
- }
- }
- }
- }
- selector.selectedKeys().clear();
- }
- }
- }
- }