ServerSocketChannel和SocketChannel


暫未考慮花大時間去學這些底層代碼,直接進入框架的學習,代碼來自網絡

 

Server

package spring.server;

import java.io.IOException;
import java.net.InetSocketAddress;
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.Iterator;

public class Server {
    /*
     * 處理器類
     */
    static class Handler {
        private int bufferSize = 1024; // 緩沖器容量
        private String localCharset = "UTF-8"; // 編碼格式

        public Handler() {
        }

        public Handler(int bufferSize) {
            this(bufferSize, null);
        }

        public Handler(String localCharset) {
            this(-1, localCharset);
        }

        public Handler(int bufferSize, String localCharset) {
            if (bufferSize > 0) {
                this.bufferSize = bufferSize;
            }
            if (localCharset != null) {
                this.localCharset = localCharset;
            }
        }

        /*
         * 連接請求處理方法
         */
        public void handleAccept(SelectionKey selectionKey) throws IOException {
            // 通過選擇器鍵獲取服務器套接字通道,通過accept()方法獲取套接字通道連接
            SocketChannel socketChannel = ((ServerSocketChannel) selectionKey.channel()).accept();
            // 設置套接字通道為非阻塞模式
            socketChannel.configureBlocking(false);
            // 為套接字通道注冊選擇器,該選擇器為服務器套接字通道的選擇器,即選擇到該SocketChannel的選擇器
            // 設置選擇器關心請求為讀操作,設置數據讀取的緩沖器容量為處理器初始化時候的緩沖器容量
            socketChannel.register(selectionKey.selector(), SelectionKey.OP_READ, ByteBuffer.allocate(bufferSize));
        }

        public void handleRead(SelectionKey selectionKey) throws IOException {
            // 獲取套接字通道
            SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
            // 獲取緩沖器並進行重置,selectionKey.attachment()為獲取選擇器鍵的附加對象
            ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
            byteBuffer.clear();
            // 沒有內容則關閉通道
            if (socketChannel.read(byteBuffer) == -1) {
                socketChannel.close();
            } else {
                // 將緩沖器轉換為讀狀態
                byteBuffer.flip();
                // 將緩沖器中接收到的值按localCharset格式編碼保存
                String receivedRequestData = Charset.forName(localCharset).newDecoder().decode(byteBuffer).toString();
                System.out.println("接收到客戶端的請求數據:" + receivedRequestData);
                // 返回響應數據給客戶端
                String responseData = "已接收到你的請求數據,響應數據為:(響應數據)";
                byteBuffer = ByteBuffer.wrap(responseData.getBytes(localCharset));
                socketChannel.write(byteBuffer);
                // 關閉通道
                socketChannel.close();
            }
        }
    }

    public static void main(String[] args) {
        try {
            // 創建ServerSocketChannel通道,綁定監聽端口為8080
            ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
            serverSocketChannel.socket().bind(new InetSocketAddress(8080));
            // 設置為非阻塞模式
            serverSocketChannel.configureBlocking(false);
            // 注冊選擇器,設置選擇器選擇的操作類型
            Selector selector = Selector.open();
            serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
            // 創建處理器
            Handler handler = new Handler(1204);
            while (true) {
                // 等待請求,每次等待阻塞3s,超過時間則向下執行,若傳入0或不傳值,則在接收到請求前一直阻塞
                if (selector.select(3000) == 0) {
                    System.out.println("等待請求超時......");
                    continue;
                }
                System.out.println("-----處理請求-----");
                // 獲取待處理的選擇鍵集合
                Iterator<SelectionKey> keyIterator = selector.selectedKeys().iterator();
                while (keyIterator.hasNext()) {
                    SelectionKey selectionKey = keyIterator.next();
                    try {
                        // 如果是連接請求,調用處理器的連接處理方法
                        if (selectionKey.isAcceptable()) {
                            handler.handleAccept(selectionKey);
                        }
                        // 如果是讀請求,調用對應的讀方法
                        if (selectionKey.isReadable()) {
                            handler.handleRead(selectionKey);
                        }
                    } catch (IOException e) {
                        keyIterator.remove();
                        continue;
                    }
                }
                // 處理完畢從待處理集合移除該選擇鍵
                keyIterator.remove();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Client

package spring.server;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class Client {
    public static void main(String[] args) throws IOException {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.connect(new InetSocketAddress("127.0.0.1", 8080));

        String newData = "New String to write to file..." + System.currentTimeMillis();

        ByteBuffer buf = ByteBuffer.allocate(48);
        buf.clear();
        buf.put(newData.getBytes());

        buf.flip();

        while (buf.hasRemaining()) {
            socketChannel.write(buf);
        }

//        socketChannel.configureBlocking(false);
//        socketChannel.connect(new InetSocketAddress("http://jenkov.com", 80));
//
//        while(! socketChannel.finishConnect() ){
//            //wait, or do something else...    
//        }
        
        socketChannel.close();
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM