1. 程式人生 > >JAVA NIO 伺服器與客戶端實現示例

JAVA NIO 伺服器與客戶端實現示例

公共類:

package com.stevex.app.nio;
 
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharacterCodingException;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
 
public class CharsetHelper {
    private static final String UTF_8 = "UTF-8";
    private static CharsetEncoder encoder = Charset.forName(UTF_8).newEncoder();
    private static CharsetDecoder decoder = Charset.forName(UTF_8).newDecoder();
     
    public static ByteBuffer encode(CharBuffer in) throws CharacterCodingException{
        return encoder.encode(in);
    }
 
    public static CharBuffer decode(ByteBuffer in) throws CharacterCodingException{
        return decoder.decode(in);
    }
}

伺服器程式碼:
package com.stevex.app.nio;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
 
public class XiaoNa {
    private ByteBuffer readBuffer;
    private Selector selector;
     
    public static void main(String[] args){
        XiaoNa xiaona = new XiaoNa();
        xiaona.init();
        xiaona.listen();
    }
     
    private void init(){
        readBuffer = ByteBuffer.allocate(1024);
        ServerSocketChannel servSocketChannel;
         
        try {
            servSocketChannel = ServerSocketChannel.open();
            servSocketChannel.configureBlocking(false);
            //繫結埠
            servSocketChannel.socket().bind(new InetSocketAddress(8383));
             
            selector = Selector.open();
            servSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException e) {
            e.printStackTrace();
        }      
    }
 
    private void listen() {
        while(true){
            try{
                selector.select();             
                Iterator ite = selector.selectedKeys().iterator();
                 
                while(ite.hasNext()){
                    SelectionKey key = (SelectionKey) ite.next();                  
                    ite.remove();//確保不重複處理
                     
                    handleKey(key);
                }
            }
            catch(Throwable t){
                t.printStackTrace();
            }                          
        }              
    }
 
    private void handleKey(SelectionKey key)
            throws IOException, ClosedChannelException {
        SocketChannel channel = null;
         
        try{
            if(key.isAcceptable()){
                ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
                channel = serverChannel.accept();//接受連線請求
                channel.configureBlocking(false);
                channel.register(selector, SelectionKey.OP_READ);
            }
            else if(key.isReadable()){
                channel = (SocketChannel) key.channel();
                readBuffer.clear();
                /*當客戶端channel關閉後,會不斷收到read事件,但沒有訊息,即read方法返回-1
                 * 所以這時伺服器端也需要關閉channel,避免無限無效的處理*/              
                int count = channel.read(readBuffer);
                 
                if(count > 0){
                    //一定需要呼叫flip函式,否則讀取錯誤資料
                    readBuffer.flip();
                    /*使用CharBuffer配合取出正確的資料
                    String question = new String(readBuffer.array());  
                    可能會出錯,因為前面readBuffer.clear();並未真正清理資料
                    只是重置緩衝區的position, limit, mark,
                    而readBuffer.array()會返回整個緩衝區的內容。
                    decode方法只取readBuffer的position到limit資料。
                    例如,上一次讀取到緩衝區的是"where", clear後position為0,limit為 1024,
                    再次讀取“bye"到緩衝區後,position為3,limit不變,
                    flip後position為0,limit為3,前三個字元被覆蓋了,但"re"還存在緩衝區中,
                    所以 new String(readBuffer.array()) 返回 "byere",
                    而decode(readBuffer)返回"bye"。            
                    */
                    CharBuffer charBuffer = CharsetHelper.decode(readBuffer); 
                    String question = charBuffer.toString(); 
                    String answer = getAnswer(question);
                    channel.write(CharsetHelper.encode(CharBuffer.wrap(answer)));
                }
                else{
                    //這裡關閉channel,因為客戶端已經關閉channel或者異常了
                    channel.close();               
                }                      
            }
        }
        catch(Throwable t){
            t.printStackTrace();
            if(channel != null){
                channel.close();
            }
        }      
    }
     
    private String getAnswer(String question){
        String answer = null;
         
        switch(question){
        case "who":
            answer = "我是小娜\n";
            break;
        case "what":
            answer = "我是來幫你解悶的\n";
            break;
        case "where":
            answer = "我來自外太空\n";
            break;
        case "hi":
            answer = "hello\n";
            break;
        case "bye":
            answer = "88\n";
            break;
        default:
                answer = "請輸入 who, 或者what, 或者where";
        }
         
        return answer;
    }
}

客戶端程式碼:
package com.stevex.app.nio;
 
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
 
 
public class Client implements Runnable{
    private BlockingQueue<String> words;
    private Random random;
     
    public static void main(String[] args) {      
        //種多個執行緒發起Socket客戶端連線請求
        for(int i=0; i<10; i++){
            Client c = new Client();
            c.init();
            new Thread(c).start();
        }      
    }
 
    @Override
    public void run() {     
        SocketChannel channel = null;
        Selector selector = null;
        try {
            channel = SocketChannel.open();
            channel.configureBlocking(false);
            //請求連線
            channel.connect(new InetSocketAddress("localhost", 8383));
            selector = Selector.open();
            channel.register(selector, SelectionKey.OP_CONNECT);
            boolean isOver = false;
             
            while(! isOver){
                selector.select();
                Iterator ite = selector.selectedKeys().iterator();
                while(ite.hasNext()){
                    SelectionKey key = (SelectionKey) ite.next();
                    ite.remove();
                     
                    if(key.isConnectable()){
                        if(channel.isConnectionPending()){
                            if(channel.finishConnect()){
                                //只有當連線成功後才能註冊OP_READ事件
                                key.interestOps(SelectionKey.OP_READ);
                                 
                                channel.write(CharsetHelper.encode(CharBuffer.wrap(getWord())));
                                sleep();
                            }
                            else{
                                key.cancel();
                            }
                        }                                              
                    }
                    else if(key.isReadable()){
                        ByteBuffer byteBuffer = ByteBuffer.allocate(128);                       
                        channel.read(byteBuffer);
                        byteBuffer.flip();
                        CharBuffer charBuffer = CharsetHelper.decode(byteBuffer);
                        String answer = charBuffer.toString(); 
                        System.out.println(Thread.currentThread().getId() + "---" + answer);
                         
                        String word = getWord();
                        if(word != null){
                            channel.write(CharsetHelper.encode(CharBuffer.wrap(word)));
                        }
                        else{
                            isOver = true;
                        }
                        sleep();                       
                    }
                }
            }                          
        } catch (IOException e) {
            e.printStackTrace();
        }
        finally{
            if(channel != null){
                try {
                    channel.close();
                } catch (IOException e) {                      
                    e.printStackTrace();
                }                  
            }
             
            if(selector != null){
                try {
                    selector.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
 
    private void init() {
        words = new ArrayBlockingQueue<String>(5);
        try {
            words.put("hi");
            words.put("who");
            words.put("what");
            words.put("where");
            words.put("bye");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }  
         
        random = new Random();
    }
     
    private String getWord(){
        return words.poll();
    }
 
    private void sleep() {
        try {
            TimeUnit.SECONDS.sleep(random.nextInt(3));
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }  
     
    private void sleep(long l) {
        try {
            TimeUnit.SECONDS.sleep(l);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}


相關推薦

JAVA NIO 伺服器客戶實現示例(程式碼1)

公共類: [java] view plain copy print? package com.stevex.app.nio;  import java.nio.ByteBuffer;  import java.nio.CharBuffer;  import j

JAVA NIO 伺服器客戶實現示例

公共類: package com.stevex.app.nio; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharacterCodingExcepti

Java NIO 伺服器客戶實現檔案下載

import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; import java.nio.chann

Java網路 伺服器客戶的簡單通訊

不登高山,不知天之高也。不臨深淵,不知地之厚也。  Java中的封裝類(Socket),在實現這個功能的時候,需要對Java中的Socket套接字的一些用法熟悉,伺服器與客戶端之間主要通過的Java中的IO流通訊。需要理解IO流的流出,流入問題。  接下來,

AndroidJava NIO實現簡單Echo伺服器客戶

上一篇用Java IO來做了個Demo,於是乎進一步,用Java NIO來做一個。NIO的優勢在於非阻塞。使用了Selector在一個執行緒裡進行輪詢,就能夠完成接入、收\發訊息的操作,不需要每建立一個連線都新啟動一個執行緒的方式。Server端程式碼:public clas

Vue+Java servlet 通過websocket實現伺服器客戶雙向通訊

1. vue程式碼 methods: { //在方法裡呼叫 this.websocketsend()傳送資料給伺服器 onConfirm () { //需要傳輸的資料 let data = { cod

JAVA整合WebSocket,實現伺服器客戶握手

                                      WebSocket實現伺服器與客戶端握手 自學的WebSocket途中遇到很多坑,希望需要使用的朋友可以少走彎路, 使用的環境:tomcat7.0,mysql,springMvc,spring,M

java Nio 使用 NioSocket 客戶服務互動實現

NioSocket 客戶端與服務端互動實現        java Nio是jdk1.4新增的io方式—–nio(new IO),這種方式在目前來說算不算new,更合適的解釋應該是non-block IO。        non-block是相對於傳統的io

Java實現簡單的Socket伺服器客戶字串通訊(適合初學者閱讀)

       近段時間,頻繁看到很多學生做畢業設計用到了Socket通訊技術,問題非常多,特寫一個小例子,希望對馬上畢業的同學有所幫助。如果希望學習的更加深入,需要掌握的知識有:面向物件、多執行緒、Socket通訊、IO流、異常處理 伺服器端程式碼: import java

二、Netty實現伺服器客戶完整互動連線實戰

        本節內容是程式碼實現伺服器與客戶端完整連線過程。整體把控netty的工作流程。我們先不要被某個類,某個api的封裝深入挖掘,這樣你會踩很多坑,陷入進去而拔不出來,後面我會一一講解,原始碼剖析工作原理。這就是我個人學習技術的一種方法,深入淺出

【隨堂筆記】unity開發中Socket的用法(一,實現伺服器客戶簡單的連結)

實現了簡單的連結,也增加了客戶端沒有連結到伺服器的自動重連 伺服器程式碼 using System; using System.Net; using System.Net.Sockets; namespace SeverSocket { class Program

搭建FTP伺服器客戶(1) - Python實現

FTP背景介紹:FTP(File Transfer Protocol)協議,顧名思義為檔案傳輸協議。由已故的Jon Postel與Joyce Reynolds開發,並於1985年10月釋出。其底層基於TCP/IP協議。FTP目前主要用於匿名下載公共檔案,也可以在兩臺跨系統的計算機之間傳輸檔案。為了實現F

【開發筆記】Unity聯網鬥地主的實現(一,伺服器客戶的資料傳遞流程)

話不多說,先上我李老師的思維導圖 大致構思了一個框架 1.首先要定義一下伺服器與客戶端的傳輸協議,必須保持一致 2.定義服務於客戶端傳輸的訊息型別,如(申請加入,同意加入,出牌,之類的) 3.定義一下牌的型別,出的牌的型別,在客戶端判斷是否可以出牌,牌型傳給伺服器,伺服器在完成三個玩家的出

C#.網路程式設計 Socket基礎(一)Socket TCP協議 實現伺服器客戶)簡單字串通訊

簡介:        本章節主要討論了Socket的入門知識,還未針對Socket的難點問題(比如TCP的無訊息邊界問題)展開討論,往後在其他章節中進行研究。 注意點: 伺服器(比如臺式電腦)的IP為1.1.1.2,那麼客戶端(其他裝置,比如手機,Ipad)連線的一定是

C#.網路程式設計 Socket基礎(三) 基於WinForm系統Socket TCP協議 實現伺服器客戶).txt.word.png等不同型別檔案傳輸

一、簡介: 前面的兩篇介紹了字串傳輸、圖片傳輸: 其實,本文針對Socket基礎(二)進一步完成,以便可以進行多種檔案傳輸。 二、基於不同的流(檔案流、記憶體流、網路等)讀寫。 1、圖片傳輸 方法一:(在客戶端用檔案流傳送(即將圖片寫到檔案流去,以便傳送),

Java伺服器客戶的通訊中物件流的使用

在使用java物件流的時候,首先要保證通訊雙方各有一個公用的包,裡面的內容相同,注意異常的丟擲。 相同的包 package common; public class User implements

Qt實現伺服器客戶傳輸文字和圖片(Qt②)

初學者記錄學習內容,如有錯誤請各位前輩指點。 此次工程完成過程借鑑了下面得兩個帖子,附上鍊接,並致以感謝: qt 寫的tcp客戶端程式實現簡單的連線接受和傳送訊息 qt寫的一個簡單的tcp伺服器程式,可以接受訊息傳送資料 好了閒話少說進入正題。 瞭解C

socket程式設計(一),實現伺服器客戶簡單通訊

本節主講客戶端向服務傳送資訊,伺服器轉發給客戶端,當然也可以稍微改一下程式碼可以實現互傳訊息,不再贅述。 難點在於伺服器端的程式碼思路: (1)主程式Socket socket=server.acc

C語言實現基本伺服器客戶

伺服器程式碼:  #include<sys/socket.h> #include<netinet/in.h> #include<sys/types.h> #include<stdlib.h> #include<stdio

C#Socket通訊基礎(非同步Socket通訊TCP)伺服器客戶

一、效果圖 二、伺服器端程式碼(原始碼下載地址:https://download.csdn.net/download/xiaochenxihua/10748789) using System; using System.Collections.Generic; using System