TCP Server工具类,BIO阻塞和非阻塞NIO

启动自定义代码的方式

WebServer Initialized Event

java 复制代码
	//@Component

	//ApplicationContext context 注入

    //@PostConstruct
    //@Async

    @EventListener(ApplicationReadyEvent.class)
    @Component
    public class TcpServerListener implements ApplicationListener<WebServerInitializedEvent> {

        @Override
        public void onApplicationEvent(WebServerInitializedEvent event) {
            //int serverPort = event.getWebServer().getPort();
            // 在此处添加代码以创建和启动 TCP 服务器
            updateServer.startServer(8082);
        }
    }

ServerSocket

基本代码

java 复制代码
            // 创建ServerSocket并绑定端口
            ServerSocket serverSocket = new ServerSocket(8080);

            // 启动一个新线程来接受客户端连接
                while (true) {
                    try {
                        // 接受客户端连接
                        Socket clientSocket = serverSocket.accept();

                        // 关闭客户端连接
                        clientSocket.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }

DataInputStream

java 复制代码
	@PostConstruct
    @Async
    public void startServer() throws Exception {
        //开启TCP Server
        ServerSocket serverSocket = new ServerSocket(8082);
        log.info("服务端打开了 Server started on port {}", 8082);
        while (true) {
            //等待连接
            Socket socket = serverSocket.accept();

            //获取 输入流
            DataInputStream inputStream = new DataInputStream(socket.getInputStream());

            DataOutputStream outputStream = new DataOutputStream(socket.getOutputStream());
            log.info("服务端收到了连接:Accepted connection from client: {}", socket.getInetAddress());
            
            //读取的字节数
            byte[] buffer = new byte[380];//1024
            //真正读取到了多少个
            int bytesRead;
            //循环进行读取
            while ((bytesRead = inputStream.read(buffer)) != -1) {
                //处理二进制数据
                processBinaryData(buffer, bytesRead, socket, outputStream);
            }//循环读取,正常每次都会读取完毕

            inputStream.close();
            outputStream.close();
            socket.close();
            
            
        }//死循环接收连接
    }//初始化方法结束*/

    //关闭输入流
    //socket.shutdownInput();
    //关闭输出流,关闭 Socket
    //socket.shutdownOutput();
    //关闭Socket
    //socket.close();

InputStreamReader 字符流

  • BufferedReader(new InputStreamReader(socket.getInputStream()))
  • new PrintWriter(socket.getOutputStream(), true)
java 复制代码
public class TcpServer {
    public static void main(String[] args) {
        try {
            //连接
            ServerSocket serverSocket = new ServerSocket(5555);
            System.out.println("服务器启动,等待客户端连接...");

            //阻塞
            Socket socket = serverSocket.accept();
            System.out.println("客户端已连接.");

            //创建 输入流。读取
            BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            //创建 输出流。写入
            PrintWriter out = new PrintWriter(socket.getOutputStream(), true);

            String message = in.readLine();
            System.out.println("收到客户端消息:" + message);
            // 解析 JSON 消息

            // 发送响应给客户端
            out.println("构建响应 JSON");

            // 关闭连接
            socket.close();
            serverSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

NIO Selector

ServerSocketChannel

java 复制代码
@Configuration
public class TcpServerConfig {
    //@Value("${tcp.ip}")
    //private String tcpIp;

    //ApplicationContext context
    //@PostConstruct
    //@Async
    @EventListener(ApplicationReadyEvent.class)
    public void startServer() {// throws IOException
        //异步执行
        //ThreadUtil.execAsync(() -> {
        try {
            
            //1.打开选择器
            Selector selector = Selector.open();
            //2.打开通道 serverSocketChannel
            ServerSocketChannel channel = ServerSocketChannel.open();
            //3.设置非阻塞
            channel.configureBlocking(false);
            //4.绑定本机IP
            channel.bind(new InetSocketAddress(tcpIp, 8082));
            //5.进行注册
            channel.register(selector, SelectionKey.OP_ACCEPT);
            log.info("===============Server started on port 8082===================");

            while (true) {
                //6.选择通道
                int readyChannels = selector.select();
                //校验下
                if (readyChannels == 0) {
                    continue;
                }
                //7.获取所有的key
                Set<SelectionKey> selectedKeys = selector.selectedKeys();
                //8.获取迭代器
                Iterator<SelectionKey> keyIterator = selectedKeys.iterator();
                //如果存在
                while (keyIterator.hasNext()) {
                    //9.获取这个key
                    SelectionKey key = keyIterator.next();
                    //10.如果是个连接
                    if (key.isAcceptable()) {
                        //11.接收这个通道
                        SocketChannel clientSocketChannel = serverSocketChannel.accept();
                        //12.非阻塞的
                        clientSocketChannel.configureBlocking(false);
                        //13.注册为可读
                        clientSocketChannel.register(selector, SelectionKey.OP_READ);
                        log.info("收到连接:Accepted connection from: {}", clientSocketChannel.getRemoteAddress());
                        
                    } else if (key.isReadable()) {
                        //14.如果是可读,获取通道
                        SocketChannel clientSocketChannel = (SocketChannel) key.channel();
                        //读取数量
                        ByteBuffer buffer = ByteBuffer.allocate(38);//1024
                        //15.真实读取到了多少个
                        int bytesRead = -1;
                        try {
                            //这里报错了,增加防护,如果没防护,这个nio就断了
                            bytesRead = clientSocketChannel.read(buffer);
                        } catch (Exception e) {
                            log.info("未读取到");
                            e.printStackTrace();
                        }
                        //未读取到 关闭
                        if (bytesRead == -1) {
                            clientSocketChannel.close();
                        } else if (bytesRead > 0) { //读到的 > 0
                            //读取到了
                            buffer.flip();
                            //读到这个字节里
                            byte[] data = new byte[bytesRead];
                            buffer.get(data);
                            //处理逻辑
                            processBinaryData(data, bytesRead, clientSocketChannel);
                            //String message = new String(data).trim();
                            //System.out.println("Received message: " + message);

                            //清理
                            buffer.clear();
                        }//读到了
                    }//是可读的
                    //移除key
                    keyIterator.remove();
                }//如果存在
            }//死循环
        } catch (Exception e) {
            e.printStackTrace();
        }
        //}, "MyTcpServerThread").start();
}
java 复制代码
    //有错误,往外层抛
    private void sendUpdateMessage(SocketChannel clientSocketChannel) {
        //转为byte
        byte[] binaryData = hexStringToBytes("dfsfsdfdsaf");
        
        //1.申请字节
        ByteBuffer buffer = ByteBuffer.allocate(binaryData.length);
        //2.放入
        buffer.put(binaryData);
        //3. 快速翻阅,浏览
        buffer.flip();
        //3.循环是否有:剩下的,遗留的;尚未使用、解决的
        while (buffer.hasRemaining()) {
            try {
                //进行写入
                clientSocketChannel.write(buffer);
                log.info("发送了一次升级的消息");
            } catch (IOException e) {
                log.info("发送升级失败");
                e.printStackTrace();
            }
        }
    }
相关推荐
苹果醋337 分钟前
React源码02 - 基础知识 React API 一览
java·运维·spring boot·mysql·nginx
Hello.Reader1 小时前
深入解析 Apache APISIX
java·apache
菠萝蚊鸭1 小时前
Dhatim FastExcel 读写 Excel 文件
java·excel·fastexcel
旭东怪2 小时前
EasyPoi 使用$fe:模板语法生成Word动态行
java·前端·word
007php0072 小时前
Go语言zero项目部署后启动失败问题分析与解决
java·服务器·网络·python·golang·php·ai编程
∝请叫*我简单先生2 小时前
java如何使用poi-tl在word模板里渲染多张图片
java·后端·poi-tl
ssr——ssss2 小时前
SSM-期末项目 - 基于SSM的宠物信息管理系统
java·ssm
一棵星2 小时前
Java模拟Mqtt客户端连接Mqtt Broker
java·开发语言
鲤籽鲲2 小时前
C# Random 随机数 全面解析
android·java·c#
zquwei3 小时前
SpringCloudGateway+Nacos注册与转发Netty+WebSocket
java·网络·分布式·后端·websocket·网络协议·spring