ServerSocketChannel和ServerSocket区别比较(SpringBoot版本)

ServerSocketChannel和ServerSocket是Java中处理网络编程的两种不同的类,它们在功能和使用方式上有一些区别

1、ServerSocketChannel:
(1)ServerSocketChannel是Java NIO库中的通道,用于监听和接受客户端连接。

(2)ServerSocketChannel提供了非阻塞模式的支持,可以通过configureBlocking(false)方法设置为非阻塞模式。

(3)ServerSocketChannel使用选择器(Selector)来管理多个通道,可以在一个线程中处理多个通道的连接请求。

(4)ServerSocketChannel接受连接后返回一个SocketChannel实例,用于与客户端进行通信。

2、ServerSocket:

(1)ServerSocket是Java标准库中的类,用于监听和接受客户端连接。

(2)ServerSocket是基于阻塞I/O模型,每个连接请求都需要在单独的线程中进行处理。

(3)ServerSocket使用accept()方法来接受客户端连接,返回一个Socket实例,用于与客户端进行通信。

主要区别和用途:

(1)ServerSocketChannel是Java NIO库中提供的非阻塞式的通道,而ServerSocket是Java标准库中的阻塞式的类。

(2)ServerSocketChannel使用选择器(Selector)来管理多个通道,可以在一个线程中处理多个连接请求,而ServerSocket通常需要为每个连接请求创建一个独立的线程。

(3)ServerSocketChannel提供了更多的灵活性,可以与其他NIO组件一起使用,如缓冲区、选择器等。而ServerSocket主要用于传统的阻塞式I/O编程。

(4)在性能方面,ServerSocketChannel通常比ServerSocket具有更好的性能和可扩展性,特别是在高并发情况下。

ServerSocketChannel最佳实践:

        使用NIO(Non-blocking I/O)来处理ServerSocket可以实现异步非阻塞的I/O操作,提高服务器的性能和扩展性。NIO使用选择器(Selector)来管理多个通道,每个通道对应一个客户端连接。以下是一个简单的示例,演示了如何使用NIO处理ServerSocket

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.util.Iterator;
import java.util.Set;

/**
 * @ClassName NIOServer
 * @Description TODO
 * @Author 俞春旺
 * @Company RBGT
 * @Date 2023年5月24日 0024 上午 09:26:26
 * @Version 1.0
 */
public class NIOServer {

    private ServerSocketChannel serverChannel;
    private Selector selector;
    private ByteBuffer buffer = ByteBuffer.allocate(1024);

    /**
     * 操作 - 执行创建一个ServerSocketChannel
     *
     * @param port 端口号
     * @return void
     * @Author 俞春旺
     * @Date 上午 09:34:04 2023年5月24日 0024
     **/
    public void start(int port) throws IOException {
        // 创建ServerSocketChannel并设置为非阻塞模式
        serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);

        // 绑定端口
        serverChannel.socket().bind(new InetSocketAddress(port));

        // 创建Selector并注册ServerSocketChannel
        selector = Selector.open();
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("NIOServer started. Listening on port " + port);

        // 处理事件循环
        while (true) {
            // 获取 - 等待事件发生
            selector.select();
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> iterator = selectedKeys.iterator();

            // 循环 - 处理链接上来的数据处理逻辑
            while (iterator.hasNext()) {
                // 获取 - 发生事件的SelectionKey
                SelectionKey key = iterator.next();
                iterator.remove();

                // 分支 - 此通道是否已准备好接受新的套接字连接
                if (key.isAcceptable()) {
                    // 设置 - 准备接口数据
                    handleAccept(key);
                } else if (key.isReadable()) {
                    // 操作 - 处理链接上报的数据
                    handleRead(key);
                }
            }
        }
    }

    /**
     * 操作 -注册迭代器,并将同道贴上可读数据标签
     *
     * @param key 发生事件的SelectionKey(每个链接标识)
     * @return void
     * @Author 俞春旺
     * @Date 上午 09:32:06 2023年5月24日 0024
     **/
    private void handleAccept(SelectionKey key) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel clientChannel = serverChannel.accept();
        clientChannel.configureBlocking(false);
        clientChannel.register(selector, SelectionKey.OP_READ);
        System.out.println("New client connected: " + clientChannel.getRemoteAddress());
    }

    /**
     * 操作 - 读取链接上报的数据
     *
     * @param key 发生事件的SelectionKey(每个链接标识)
     * @return void
     * @Author 俞春旺
     * @Date 上午 09:32:55 2023年5月24日 0024
     **/
    private void handleRead(SelectionKey key) throws IOException {
        SocketChannel clientChannel = (SocketChannel) key.channel();
        buffer.clear();
        int bytesRead = clientChannel.read(buffer);
        if (bytesRead > 0) {
            buffer.flip();
            byte[] data = new byte[buffer.limit()];
            buffer.get(data);
            String message = new String(data);
            System.out.println("Received message from client: " + message);
            // 处理接收到的消息

            // 回复消息给客户端
            String response = "Response from server";
            buffer.clear();
            buffer.put(response.getBytes());
            buffer.flip();
            clientChannel.write(buffer);
        } else if (bytesRead == -1) {
            // 客户端断开连接
            clientChannel.close();
            System.out.println("Client disconnected: " + clientChannel.getRemoteAddress());
        }
    }

    /**
     * 操作 - 测试链接
     *
     * @param args
     * @return void
     * @Author 俞春旺
     * @Date 上午 09:33:43 2023年5月24日 0024
     **/
    public static void main(String[] args) {
        // 指定服务器端口
        int port = 8080;
        try {
            NIOServer nioServer = new NIOServer();
            nioServer.start(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

        在上述代码中,我们使用ServerSocketChannel来创建服务器端通道,并将其配置为非阻塞模式。然后,我们绑定端口并将服务器通道注册到选择器(Selector)中,以便监听连接事件(OP_ACCEPT)。

        在事件循环中,我们调用selector.select()来等待事件发生。一旦有事件发生(如新连接到达或数据可读),selector.select()会返回,我们可以通过selector.selectedKeys()获取到发生事件的SelectionKey集合。 然后,我们遍历SelectionKey集合,并根据不同的事件类型进行处理。

        如果是OP_ACCEPT事件,表示有新的客户端连接到达,我们调用handleAccept()方法来处理该连接。在handleAccept()方法中,我们获取到新的客户端通道,并将其注册到选择器中,以便监听数据读取事件(OP_READ)

        如果是OP_READ事件,表示有数据可读,我们调用handleRead()方法来处理读取数据。在handleRead()方法中,我们从客户端通道中读取数据到缓冲区,并进行相应的处理。在本示例中,我们将收到的消息打印输出,并回复一个简单的响应给客户端。

        如果bytesRead负值,表示客户端断开连接,我们关闭客户端通道并进行相应的处理。

        最后,在main方法中,我们创建一个NIOServer对象,并调用start方法来启动服务器。 请注意,上述示例仅演示了如何使用NIO处理ServerSocket,处理的消息内容和业务逻辑可能需要根据实际需求进行调整和扩展。

        此外,NIO编程涉及到了更多的概念和操作,如通道(Channel)、缓冲区(Buffer)、选择器(Selector)等。深入理解NIO编程模型和相关API是很重要的,以便正确和高效地处理I/O操作。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值