ServerSocketChannel介紹與應用

一、ServerSocketChannel概述

ServerSocketChannel是Java NIO提供的一種與傳統IO不同的新型I/O Channel,它可以同時處理多個客戶端請求。通常它會被用於服務端程序,監聽客戶端的連接請求,並創建相應的SocketChannel進行處理。

import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerSocketChannelDemo {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            //處理客戶端請求
        }
    }
}

二、ServerSocketChannel與SocketChannel的區別

ServerSocketChannel和SocketChannel都是Java NIO提供的I/O Channel,但是它們的用途不同。ServerSocketChannel被用於監聽客戶端連接請求,而SocketChannel則是客戶端與服務端進行通信的通道。

ServerSocketChannel是一個單向的Channel,只能接收連接,而不能發送數據。而SocketChannel則是一個雙向的Channel,既可以發送數據,也可以接收數據。

三、ServerSocketChannel的非阻塞模式

ServerSocketChannel可以通過設置非阻塞模式來提高處理效率。在非阻塞模式下,當沒有客戶端連接請求時,它不會一直等待,而是會直接返回null,程序可以繼續運行。因此,在while循環中,需要對返回的SocketChannel進行非空判斷。

import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class ServerSocketChannelDemo {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            if (socketChannel != null) {
                //處理客戶端請求
            }
        }
    }
}

四、ServerSocketChannel的Selector選擇器

ServerSocketChannel的重要特性是可以組合Selector選擇器一起使用,從而可以同時管理多個客戶端的請求。它可以將所有的SocketChannel註冊到同一個Selector中,當有連接請求時,Selector會通知相關的SocketChannel進行處理。

import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;

public class SelectorServerSocketChannelDemo {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.configureBlocking(false);
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        
        Selector selector = Selector.open();
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        
        while (true) {
            selector.select();
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            for (SelectionKey selectionKey : selectionKeys) {
                if (selectionKey.isAcceptable()) {
                    ServerSocketChannel ssc = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel = ssc.accept();
                    socketChannel.configureBlocking(false);
                    socketChannel.register(selector, SelectionKey.OP_READ);
                } else if (selectionKey.isReadable()) {
                    SocketChannel channel = (SocketChannel) selectionKey.channel();
                    //讀取客戶端數據
                }
            }
            selectionKeys.clear();
        }
    }
}

五、ServerSocketChannel的多線程應用

ServerSocketChannel同樣可以通過多線程的方式進行應用,採用線程池可以使程序更高效地處理多個客戶端連接請求。在每個線程中,可以針對每個客戶端創建一個SocketChannel進行處理。

import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolServerSocketChannelDemo {
    public static void main(String[] args) throws Exception {
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        serverSocketChannel.socket().bind(new InetSocketAddress(8080));
        
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        
        while (true) {
            SocketChannel socketChannel = serverSocketChannel.accept();
            executorService.execute(new SocketChannelHandler(socketChannel));
        }
    }
}

class SocketChannelHandler implements Runnable {
    private SocketChannel socketChannel;

    public SocketChannelHandler(SocketChannel socketChannel) {
        this.socketChannel = socketChannel;
    }

    public void run() {
        //處理客戶端請求
    }
}

原創文章,作者:PJPRR,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/331840.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
PJPRR的頭像PJPRR
上一篇 2025-01-20 14:11
下一篇 2025-01-20 14:11

發表回復

登錄後才能評論