一、前言
该项目源码基于java nio的非阻塞I/O的消息事件的方式进行通信,主要包含Server服务端通信代码和Client客户端代码(完整项目源码参见相关资源下载页面)。
二、代码说明
1. Server服务端代码
import java.io.IOException;@b@import java.net.InetSocketAddress;@b@import java.nio.ByteBuffer;@b@import java.nio.CharBuffer;@b@import java.nio.channels.Selector;@b@import java.nio.channels.ServerSocketChannel;@b@import java.nio.channels.SelectionKey;@b@import java.nio.channels.SocketChannel;@b@import java.nio.charset.Charset;@b@import java.nio.charset.CharsetDecoder;@b@import java.nio.charset.CharsetEncoder;@b@import java.util.Iterator;@b@@b@public class Server {@b@ private static final int SERVERPORT=8890;@b@ public static void main(String[] args) {@b@ Selector selector = null;@b@ ServerSocketChannel server = null;@b@ try{@b@ selector = Selector.open();@b@ server = ServerSocketChannel.open();@b@ InetSocketAddress ip = new InetSocketAddress(SERVERPORT);@b@ server.socket().bind(ip);@b@ server.configureBlocking(false);@b@ server.register(selector,SelectionKey.OP_ACCEPT);@b@ System.out.println("服务器开始接受客户端连接");@b@ @b@ while(true){@b@// select@b@ try {@b@ selector.select();@b@ } catch (Exception e) {@b@ // TODO: handle exception@b@// System.out.println("select 错误");@b@ }@b@ Iterator<SelectionKey>it = selector.selectedKeys().iterator();@b@// deal everyone@b@ while(it.hasNext()){@b@ SelectionKey key = it.next();@b@ it.remove();@b@// acceptable@b@ if(key.isAcceptable()){@b@ ServerSocketChannel server2 = (ServerSocketChannel)key.channel();@b@ SocketChannel channel = server2.accept();@b@ channel.configureBlocking(false);@b@ channel.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);@b@ System.out.println("客户端:"@b@ + channel.socket().getInetAddress().getHostName() + ":"@b@ + channel.socket().getPort() + " 连接上了");@b@ }@b@// readable@b@ if(key.isReadable()){@b@// System.out.println("可读");@b@ SocketChannel channel = (SocketChannel)key.channel();@b@ CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();@b@ ByteBuffer buffer = ByteBuffer.allocate(50);@b@ try{@b@ channel.read(buffer);@b@ }catch(IOException e){@b@// 客户端异常断开连接@b@ System.out.println("客户端:"@b@ + channel.socket().getInetAddress().getHostName() + ":"@b@ + channel.socket().getPort() + " 已断开连接");@b@ channel.close();@b@ continue;@b@ }@b@ buffer.flip();@b@ String msg = decoder.decode(buffer).toString();@b@@b@ if (msg.equals("退出!@#$%")) {@b@// 客户端主动断开连接@b@ System.out.println("客户端:"@b@ + channel.socket().getInetAddress().getHostName() + ":"@b@ + channel.socket().getPort() + " 已断开连接");@b@ channel.close();@b@ continue;@b@ }@b@ System.out.println(@b@ channel.socket().getInetAddress().getHostName() + ":"@b@ + channel.socket().getPort() + ":" + msg);@b@ @b@ if (key.isWritable()) {@b@// System.out.println("可写");@b@ CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();@b@ try {@b@ channel.write(encoder.encode(CharBuffer.wrap("server receive your message ")));@b@ } catch (IOException e) {@b@ // TODO: handle exception@b@ System.out.println("写入io错误");@b@ }@b@ }@b@ }@b@ }@b@ }@b@ }catch(IOException e){@b@ e.printStackTrace();@b@ }@b@ finally{@b@ try{@b@ selector.close();@b@ server.close();@b@ }catch(IOException e){}@b@ }@b@ }@b@}
2. Client客户端代码
import java.io.*;@b@@b@public class Client {@b@@b@ public static void main(String[] args) {@b@ ClientThread client = new ClientThread();@b@ client.start();@b@ BufferedReader sin = new BufferedReader(new InputStreamReader(System.in));@b@ try{@b@ String readline;@b@ while((readline = sin.readLine())!=null){@b@ if(readline.equals("bye")){@b@ client.close();@b@ System.exit(0);@b@ }@b@ client.send(readline);@b@ }@b@ }catch(IOException e){@b@ e.printStackTrace();@b@ }@b@ }@b@}
import java.io.IOException;@b@import java.net.InetSocketAddress;@b@import java.nio.ByteBuffer;@b@import java.nio.CharBuffer;@b@import java.nio.channels.Selector;@b@import java.nio.channels.SelectionKey;@b@import java.nio.channels.SocketChannel;@b@import java.nio.charset.Charset;@b@import java.nio.charset.CharsetDecoder;@b@import java.nio.charset.CharsetEncoder;@b@import java.util.Iterator;@b@@b@public class ClientThread extends Thread {@b@@b@ private CharsetDecoder decoder = Charset.forName("UTF-8").newDecoder();@b@ private CharsetEncoder encoder = Charset.forName("UTF-8").newEncoder();@b@ private Selector selector = null;@b@ private SocketChannel socket = null;@b@ private SelectionKey clientKey = null;@b@@b@ public ClientThread(){@b@ try{@b@ selector = Selector.open();@b@ socket = SocketChannel.open();@b@ socket.configureBlocking(false);@b@ clientKey = socket.register(selector, SelectionKey.OP_CONNECT);@b@ InetSocketAddress ip = new InetSocketAddress("localhost",8890);@b@ socket.connect(ip);@b@ }catch(IOException e){@b@ e.printStackTrace();@b@ }@b@ }@b@ public void run(){@b@ try{@b@ while(true){@b@ selector.select(1);@b@ Iterator<SelectionKey>it = selector.selectedKeys().iterator();@b@ while(it.hasNext()){@b@ SelectionKey key = it.next();@b@ it.remove();@b@ if(key.isConnectable()){@b@ SocketChannel channel = (SocketChannel)key.channel();@b@ if(channel.isConnectionPending())@b@ channel.finishConnect();@b@ channel.register(selector, SelectionKey.OP_READ);@b@ System.out.println("连接服务器端成功!");@b@ }else if(key.isReadable()){@b@ SocketChannel channel = (SocketChannel)key.channel();@b@ ByteBuffer buffer = ByteBuffer.allocate(50);@b@ try{@b@ channel.read(buffer);@b@ }catch(IOException e){@b@ System.out.println("与服务器:"@b@ + channel.socket().getInetAddress().getHostName() + ":"@b@ + channel.socket().getPort() + "的连接已断开");@b@ channel.close();@b@ continue;//这一句是为了让你看到打印信息@b@ }@b@ buffer.flip();@b@ String msg = decoder.decode(buffer).toString();@b@ System.out.println(@b@ channel.socket().getInetAddress().getHostName() + ":"@b@ + channel.socket().getPort() + ":" + msg);@b@ }@b@ }@b@ }@b@ @b@ }catch(IOException e){@b@ e.printStackTrace();@b@ }@b@ finally{@b@ try{@b@ selector.close();@b@ socket.close();@b@ }catch(IOException e){}@b@ }@b@ }@b@@b@ public void send(String msg){@b@ try{@b@ SocketChannel client = (SocketChannel)clientKey.channel();@b@ client.write(encoder.encode(CharBuffer.wrap(msg)));@b@ }catch(Exception e){@b@ System.out.println("发送信息失败");@b@ e.printStackTrace();@b@ }@b@ }@b@@b@ public void close(){@b@ try{@b@ selector.close();@b@ socket.close();@b@ }catch(IOException e){@b@ e.printStackTrace();@b@ }@b@ }@b@}