首页 > 编程语言 >12.30 java网络编程之socket编程(NIO多路复用版本) socket编程大作业答案

12.30 java网络编程之socket编程(NIO多路复用版本) socket编程大作业答案

时间:2025-01-04 23:33:10浏览次数:10  
标签:key java socket 编程 ByteBuffer import 服务器 客户端

在本次项目中,我们将实现一个简单的客户端-服务器(Client-Server)通信模型。通过这个项目,你将学习到如何使用Java的SocketCh和ServerSocket类来创建网络连接,进行数据的发送和接收。该项目不仅涵盖了Socket编程的基础知识,还将帮助你理解网络通信中的重要概念,如TCP/IP协议、阻塞与非阻塞I/O等。本socket教程基于NIO的SocketChannal等完成

同时我们会将他部署到自己的云服务器中实现远程消息收发

传统套接字:基于流(Stream),默认为阻塞I/O,在传统的Java Socket编程中,通信是基于流(Stream)的模型。流是一种单向的数据传输机制,分为输入流(InputStream)和输出流(OutputStream)。
缓冲区(Buffer):

NIO的数据读写是基于缓冲区(Buffer)的。缓冲区是一个固定大小的内存块,用于临时存储数据。

缓冲区提供了对数据的结构化访问,例如可以通过position、limit和capacity等属性来管理数据的读写位置。

常见的缓冲区类型包括ByteBuffer、CharBuffer、IntBuffer等

代码流程

服务器

  1. 首先是创建selctor(NIO核心组件),
  2. 创建serverSocketChannal
    这个serverSocketChannal就理解为以前的ServerSocket就行了,都是监听端口是否有信息的
    之前的ServerSocket是只要有一个消息,我们就会返回一个socket
  3. 绑定serverSocketChannal到selctor
  4. 然后就死循环等待消息到来(有两种连接消息/读消息)
    这里会/获取发生事件的 SelectionKey 集合(我们知道NIO多路复用底层用的是epoll,也就是不会遍历所有监听的客户端,而是直接获取)
    然后再对遍历集合中的key我们就可以从里面后获取Socketchannel
    然后对Socketchannel 就和socket一样,可以从里面获取消息以及发送消息

客户端

  1. 创建一个socketchannel,然后连接服务器
  2. 向socketchannel中写东西
  3. 同时可以接受服务器的东西
  4. 关闭socketchannel

服务器代码

package coml.zy;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

public class Main {
    public static void main(String[] args) throws IOException {
        // 创建 Selector
        Selector selector = Selector.open();

        // 创建 ServerSocketChannel 并绑定端口
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();
        //此处应该写0.0.0.0而非localhost
        serverSocketChannel.bind(new InetSocketAddress("0.0.0.0", 12345));
        serverSocketChannel.configureBlocking(false); // 设置为非阻塞模式

        // 将 ServerSocketChannel 注册到 Selector,监听 ACCEPT 事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("服务器已启动,等待客户端连接...");

        while (true) {
            // 阻塞等待事件发生
            selector.select();

            // 获取发生事件的 SelectionKey 集合
            Set<SelectionKey> selectedKeys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = selectedKeys.iterator();

            while (keyIterator.hasNext()) {
                SelectionKey key = keyIterator.next();
                keyIterator.remove(); // 处理完后移除

                if (key.isAcceptable()) {
                    // 处理客户端连接
                    handleAccept(key, selector);
                } else if (key.isReadable()) {
                    // 处理客户端数据读取
                    handleRead(key);
                }
            }
        }
    }

    // 处理客户端连接
    private static void handleAccept(SelectionKey key, Selector selector) throws IOException {
        ServerSocketChannel serverChannel = (ServerSocketChannel) key.channel();
        SocketChannel clientChannel = serverChannel.accept(); // 接受客户端连接
        clientChannel.configureBlocking(false); // 设置为非阻塞模式

        // 将客户端通道注册到 Selector,监听 READ 事件
        clientChannel.register(selector, SelectionKey.OP_READ);
        System.out.println("客户端已连接:" + clientChannel.getRemoteAddress());
    }

    // 处理客户端数据读取
    private static void handleRead(SelectionKey key) throws IOException {
        SocketChannel clientChannel = (SocketChannel) key.channel();
        ByteBuffer buffer = ByteBuffer.allocate(1024);

        int bytesRead = clientChannel.read(buffer); // 读取客户端数据
        if (bytesRead == -1) {
            // 客户端断开连接
            System.out.println("客户端已断开:" + clientChannel.getRemoteAddress());
            clientChannel.close(); // 关闭通道
            key.cancel(); // 移除相关的 SelectionKey
            return;
        }

        if (bytesRead > 0) {
            buffer.flip(); // 切换为读模式
            byte[] data = new byte[buffer.remaining()];
            buffer.get(data);
            String message = new String(data);
            System.out.println("收到客户端消息:" + message);

            // 向客户端发送响应
            String response = "服务器已收到你的消息:" + message;
            ByteBuffer responseBuffer = ByteBuffer.wrap(response.getBytes());
            clientChannel.write(responseBuffer);
        }
    }
}

然后是一个简单的客户端

package coml.zy;

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

public class NioClient2 {
	//这里可以换成远程服务器的版本,假如是本地就localhost
    private static final String SERVER_HOST = "localhost";
    private static final int SERVER_PORT = 12345;

    public static void main(String[] args) {
        try {
            startClient();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static void startClient() throws IOException {
        // 创建 SocketChannel 并连接服务器
        SocketChannel socketChannel = SocketChannel.open();
        //此处应该写0.0.0.0而非localhost
        socketChannel.connect(new InetSocketAddress(SERVER_HOST, SERVER_PORT));
        System.out.println("已连接到服务器,可以开始发送消息。输入 'exit' 退出。");

        Scanner scanner = new Scanner(System.in);
        while (true) {
            // 读取用户输入
            System.out.print("请输入消息:");
            String message = scanner.nextLine();

            // 如果用户输入 'exit',则退出循环
            if ("exit".equalsIgnoreCase(message)) {
                break;
            }

            // 发送消息给服务器
            ByteBuffer buffer = ByteBuffer.wrap(message.getBytes());
            socketChannel.write(buffer);
            System.out.println("已发送消息:" + message);

            // 接收服务器的响应
            ByteBuffer responseBuffer = ByteBuffer.allocate(1024);
            int bytesRead = socketChannel.read(responseBuffer);
            if (bytesRead > 0) {
                responseBuffer.flip();
                byte[] data = new byte[responseBuffer.remaining()];
                responseBuffer.get(data);
                String response = new String(data);
                System.out.println("收到服务器响应:" + response);
            }
        }

        // 关闭连接
        socketChannel.close();
        System.out.println("客户端已断开连接。");
    }
}

运行方式
在本地
是将这个服务器打包成JAR包,然后双击,就算是运行了

远程部署
用docker部署,打包成jar包之后
Docker flie

# 使用 OpenJDK 的基础镜像
FROM openjdk:11.0-jre-buster

# 设置时区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone


COPY  socketDemo-1.0-SNAPSHOT.jar /app.jar


ENTRYPOINT ["java", "-jar", "/app.jar"]

先build再这个run
运行效果
在这里插入图片描述
在这里插入图片描述
该示例代码由deepSeek大模型辅助生成,deepSeek自我感觉确实比其他的国产大模型靠谱一点,另外比gpt要方便(网络/生成快),gemini最快最傻比国产还傻

标签:key,java,socket,编程,ByteBuffer,import,服务器,客户端
From: https://blog.csdn.net/weixin_45448575/article/details/144813935

相关文章

  • java简单算法题001(保姆级教学)
    问题描述在一个班级中,每位同学都拿到了一张卡片,上面有一个整数。有趣的是,除了一个数字之外,所有的数字都恰好出现了两次。现在需要你帮助班长小C快速找到那个拿了独特数字卡片的同学手上的数字是什么。要求:设计一个算法,使其时间复杂度为O(n),其中n是班级的人数。尽量减少额......
  • PL/SQL语言的并发编程
    PL/SQL语言的并发编程引言在现代数据库应用中,通常需要处理大量的数据,并发编程成为了提升系统性能的有效手段。PL/SQL(ProceduralLanguage/SQL)作为Oracle数据库的一种过程化语言,具备强大的数据处理能力。在大规模数据处理和事务管理中,PL/SQL的并发编程能力显得尤为重要。本......
  • JavaScript语言的计算机基础
    JavaScript语言的计算机基础引言自1995年由网景公司(Netscape)推出以来,JavaScript已经从一个简单的客户端脚本语言发展成为一种广泛使用的编程语言。如今,它不仅在网页开发中扮演着不可或缺的角色,还成为后端开发、移动应用开发、甚至桌面应用开发的一部分。在本文中,我们将探......
  • Python语言的编程范式
    Python语言的编程范式Python是一种广泛使用的高级编程语言,它因其简单易读的语法和强大的功能而受到程序员的喜爱。自1991年由荷兰人GuidolvanRossum首次发布以来,Python的发展迅速,其应用范围涵盖了Web开发、数据分析、人工智能、科学计算、自动化等多个领域。本文将深入探......
  • Java 大视界 -- Java 大数据图像与视频处理:基于深度学习与大数据框架(九)
           ......
  • 【Java中的IO详解】
    Java中的IO详解Java的IO(输入/输出)系统是一个复杂且功能丰富的库,它提供了多种方式来处理数据流。概念流(Stream):流是用于表示一系列有序的数据元素的抽象。在Java中,所有的I/O操作都是通过流完成的。字节流(ByteStream):以字节为单位进行读写,适用于二进制数据。字符......
  • Java实现验证码识别
    一、准备工作安装JDK并配置环境变量。安装Eclipse或IntelliJIDEA作为开发工具。安装SeleniumWebDriver库和Tesseract-OCR库。二、打开网站并设置浏览器窗口首先,打开浏览器并将窗口最大化,以确保每次截取的图片都是相同的大小:javaimportorg.openqa.selenium.WebDriver;im......
  • java基于Spark的温布尔登特色赛赛事数据分析预测及算法实现
    目录系统实现截图开发核心技术介绍技术栈核心代码部分展示操作手册视频演示/源码获取系统实现截图开发核心技术介绍springboot+Element-UI+vue本系统采用MVVM模式,开发框架使用SpringBoot框架,开发工具使用IDEA,VisualStudioCode,Web服务器使用Tomcat,数据库服......
  • Java笔记(一)内部类
    这是关于我对内部类理解的笔记,可能写的不怎么好,所以虚心接受大佬的指导内部类(NestedClass)定义在一个类中的另一个类被叫做内部类(InnerClass),内部类有四种类型成员内部类、静态内部类、局部内部类、匿名内部类成员内部类、局部内部类、匿名内部类中成员内部类//inner......
  • 基于ssm的游戏购买下载平台(有报告)。Javaee项目,ssm项目。
    演示视频:基于ssm的游戏购买下载平台(有报告)。Javaee项目,ssm项目。项目介绍:采用M(model)V(view)C(controller)三层体系结构,通过Spring+SpringMvc+Mybatis+Jsp+Maven来实现。MySQL数据库作为系统数据储存平台,实现了基于B/S结构的Web系统。系统设计思想一个成功......