java nio SocketChannel 服務器端與多客戶端 信息交互(聊天功能)
服務器端:
Java代碼 :
- import java.io.IOException;
- import java.net.InetSocketAddress;
- import java.net.ServerSocket;
- import java.net.Socket;
- 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;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.Set;
- public class NIOSServer {
- private int port = 8888;
- //解碼buffer
- private Charset cs = Charset.forName("gbk");
- /*接受數據緩沖區*/
- private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
- /*發送數據緩沖區*/
- private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
- /*映射客戶端channel */
- private Map<String, SocketChannel> clientsMap = new HashMap<String, SocketChannel>();
- private static Selector selector;
- public NIOSServer(int port){
- this.port = port;
- try {
- init();
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- private void init() throws IOException{
- /*
- *啟動服務器端,配置為非阻塞,綁定端口,注冊accept事件
- *ACCEPT事件:當服務端收到客戶端連接請求時,觸發該事件
- */
- ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
- serverSocketChannel.configureBlocking(false);
- ServerSocket serverSocket = serverSocketChannel.socket();
- serverSocket.bind(new InetSocketAddress(port));
- selector = Selector.open();
- serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
- System.out.println("server start on port:"+port);
- }
- /**
- * 服務器端輪詢監聽,select方法會一直阻塞直到有相關事件發生或超時
- */
- private void listen(){
- while (true) {
- try {
- selector.select();//返回值為本次觸發的事件數
- Set<SelectionKey> selectionKeys = selector.selectedKeys();
- for(SelectionKey key : selectionKeys){
- handle(key);
- }
- selectionKeys.clear();//清除處理過的事件
- } catch (Exception e) {
- e.printStackTrace();
- break;
- }
- }
- }
- /**
- * 處理不同的事件
- */
- private void handle(SelectionKey selectionKey) throws IOException {
- ServerSocketChannel server = null;
- SocketChannel client = null;
- String receiveText=null;
- int count=0;
- if (selectionKey.isAcceptable()) {
- /*
- * 客戶端請求連接事件
- * serversocket為該客戶端建立socket連接,將此socket注冊READ事件,監聽客戶端輸入
- * READ事件:當客戶端發來數據,并已被服務器控制線程正確讀取時,觸發該事件
- */
- server = (ServerSocketChannel) selectionKey.channel();
- client = server.accept();
- client.configureBlocking(false);
- client.register(selector, SelectionKey.OP_READ);
- } else if (selectionKey.isReadable()) {
- /*
- * READ事件,收到客戶端發送數據,讀取數據后繼續注冊監聽客戶端
- */
- client = (SocketChannel) selectionKey.channel();
- rBuffer.clear();
- count = client.read(rBuffer);
- if (count > 0) {
- rBuffer.flip();
- receiveText = String.valueOf(cs.decode(rBuffer).array());
- System.out.println(client.toString()+":"+receiveText);
- dispatch(client, receiveText);
- client = (SocketChannel) selectionKey.channel();
- client.register(selector, SelectionKey.OP_READ);
- }
- }
- }
- /**
- * 把當前客戶端信息 推送到其他客戶端
- */
- private void dispatch(SocketChannel client,String info) throws IOException{
- Socket s = client.socket();
- String name = "["+s.getInetAddress().toString().substring(1)+":"+Integer.toHexString(client.hashCode())+"]";
- if(!clientsMap.isEmpty()){
- for(Map.Entry<String, SocketChannel> entry : clientsMap.entrySet()){
- SocketChannel temp = entry.getValue();
- if(!client.equals(temp)){
- sBuffer.clear();
- sBuffer.put((name+":"+info).getBytes());
- sBuffer.flip();
- //輸出到通道
- temp.write(sBuffer);
- }
- }
- }
- clientsMap.put(name, client);
- }
- public static void main(String[] args) throws IOException {
- NIOSServer server = new NIOSServer(7777);
- server.listen();
- }
- }
客戶端,可運行啟動多個:
Java代碼:
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- 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.Date;
- import java.util.Set;
- public class NIOClient {
- /*發送數據緩沖區*/
- private static ByteBuffer sBuffer = ByteBuffer.allocate(1024);
- /*接受數據緩沖區*/
- private static ByteBuffer rBuffer = ByteBuffer.allocate(1024);
- /*服務器端地址*/
- private InetSocketAddress SERVER;
- private static Selector selector;
- private static SocketChannel client;
- private static String receiveText;
- private static String sendText;
- private static int count=0;
- public NIOClient(int port){
- SERVER = new InetSocketAddress("localhost", port);
- init();
- }
- public void init(){
- try {
- /*
- * 客戶端向服務器端發起建立連接請求
- */
- SocketChannel socketChannel = SocketChannel.open();
- socketChannel.configureBlocking(false);
- selector = Selector.open();
- socketChannel.register(selector, SelectionKey.OP_CONNECT);
- socketChannel.connect(SERVER);
- /*
- * 輪詢監聽客戶端上注冊事件的發生
- */
- while (true) {
- selector.select();
- Set<SelectionKey> keySet = selector.selectedKeys();
- for(final SelectionKey key : keySet){
- handle(key);
- };
- keySet.clear();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- public static void main(String[] args) throws IOException {
- NIOClient client = new NIOClient(7777);
- }
- private void handle(SelectionKey selectionKey) throws IOException{
- if (selectionKey.isConnectable()) {
- /*
- * 連接建立事件,已成功連接至服務器
- */
- client = (SocketChannel) selectionKey.channel();
- if (client.isConnectionPending()) {
- client.finishConnect();
- System.out.println("connect success !");
- sBuffer.clear();
- sBuffer.put((new Date().toLocaleString()+" connected!").getBytes());
- sBuffer.flip();
- client.write(sBuffer);//發送信息至服務器
- /* 原文來自站長網
- * 啟動線程一直監聽客戶端輸入,有信心輸入則發往服務器端
- * 因為輸入流是阻塞的,所以單獨線程監聽
- */
- new Thread(){
- @Override
- public void run() {
- while(true){
- try {
- sBuffer.clear();
- InputStreamReader input = new InputStreamReader(System.in);
- BufferedReader br = new BufferedReader(input);
- sendText = br.readLine();
- /*
- * 未注冊WRITE事件,因為大部分時間channel都是可以寫的
- */
- sBuffer.put(sendText.getBytes());
- sBuffer.flip();
- client.write(sBuffer);
- } catch (IOException e) {
- e.printStackTrace();
- break;
- }
- }
- };
- }.start();
- }
- //注冊讀事件
- client.register(selector, SelectionKey.OP_READ);
- } else if (selectionKey.isReadable()) {
- /*
- * 讀事件觸發
- * 有從服務器端發送過來的信息,讀取輸出到屏幕上后,繼續注冊讀事件
- * 監聽服務器端發送信息
- */
- client = (SocketChannel) selectionKey.channel();
- rBuffer.clear();
- count=client.read(rBuffer);
- if(count>0){
- receiveText = new String( rBuffer.array(),0,count);
- System.out.println(receiveText);
- client = (SocketChannel) selectionKey.channel();
- client.register(selector, SelectionKey.OP_READ);
- }
- }
- }
- } 原文來自java教程網 http://www.software8.co/wzjs/java/ 歡迎java愛好者前來投稿