java案例-服务端与客户端(传输对象)

news2024/11/26 23:55:51

需求

在这里插入图片描述

代码

  • SysUser 用户类
  • Operation 操作类
  • Client 客户端
  • Server 服务端
  • ServerReaderThread 服务端线程类

SysUser 用户类

  • 需要实现Serializable 方便序列化,传输对象
public class SysUser implements Serializable {
    private String username;
    private String password;

    public SysUser() {
    }

    public SysUser(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public String getUsername() {
        return this.username;
    }

    public String getPassword() {
        return this.password;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "SysUser{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

操作类

操作方法和被操作的用户

public class Operation implements Serializable {
    private String operation;
    private SysUser sysUser;

    public Operation() {
    }

    public Operation(String operation, SysUser sysUser) {
        this.operation = operation;
        this.sysUser = sysUser;
    }

    public String getOperation() {
        return this.operation;
    }

    public SysUser getSysUser() {
        return this.sysUser;
    }

    public void setOperation(String operation) {
        this.operation = operation;
    }

    public void setSysUser(SysUser sysUser) {
        this.sysUser = sysUser;
    }

    @Override
    public String toString() {
        return "Operation{" +
                "operation='" + operation + '\'' +
                ", sysUser=" + sysUser +
                '}';
    }
}

客户端

  • 本例是一个长连接:一直挂在服务器端,那么服务器端的读取线程中就必须要有一个while 循环 不断读取此长连接的内容
  • 如果不使用本例的方法,而是每次都创建新的socket 连接服务器,那么读取线程中就必须要有一个while 循环就是非必要的,因为每次连接只会发送一次,等待服务器端响应之后,需要关闭此socket,这就是短连接
// 该类是一个客户端类
public class Client {

    private static Scanner scanner = new Scanner(System.in);



    public static void main(String[] args) throws IOException {
        start();
    }


    // 该方法是一个启动方法
    public static void start() throws IOException {

        Scanner scanner = new Scanner(System.in);

        Socket socket = new Socket("127.0.0.1",8888);

        // 此处加死循环 是为了让客户端一直运行
        while (true){

            System.out.println("请输入你要进行的操作");
            System.out.println("1.注册");
            System.out.println("2.登录");
            System.out.println("3.退出");
            String i = scanner.next();
            switch (i){
                case "1":
                    System.out.println("注册");
                    register(socket);
                    break;
                case "2":
                    System.out.println("登录");
                    login(socket);
                    break;
                case "3":
                    System.out.println("退出");
                    socket.close();
                    break;
                default:
                    System.out.println("输入错误,请重新输入");
            }
        }
    }

    // 该方法是一个注册方法
    public static void register(Socket socket) throws IOException {

        System.out.println("请输入用户名");
        String username = scanner.next();
        System.out.println("请输入密码");
        String password = scanner.next();
        SysUser sysUser = new SysUser(username,password);
        Operation operation = new Operation("register",sysUser);
        // 获取输出流
        requestAndRespond(socket, operation);

    }

    private static void requestAndRespond(Socket socket, Operation operation) throws IOException {
        OutputStream outputStream = socket.getOutputStream();
        // 封装输出流为对象输出流
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
        // 写出对象
        objectOutputStream.writeObject(operation);
        objectOutputStream.flush();
        // 不要关闭流 否则会关闭socket
        //objectOutputStream.close();

        // 获取响应
        InputStream inputStream = socket.getInputStream();
        DataInputStream dataInputStream = new DataInputStream(inputStream);
        String response = dataInputStream.readUTF();
        System.out.println(response);

    }

    // 该方法是一个登录方法
    public static void login(Socket socket) throws IOException {
        System.out.println("请输入用户名");
        String username = scanner.next();
        System.out.println("请输入密码");
        String password = scanner.next();
        SysUser sysUser = new SysUser(username,password);
        Operation operation = new Operation("login",sysUser);
        // 获取输出流
        requestAndRespond(socket, operation);
    }
}

服务器端

// 该类是一个服务端类
public class Server {

    // 模拟数据库
    public static final File file = new File("test999.txt");

    public static ServerSocket serverSocket;

    //  创建线程池
    public static final ExecutorService pool =  new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS,
            new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

    static {
        try {
            serverSocket = new ServerSocket(8888);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args) throws IOException {
        start();

    }

    // 该方法是一个启动方法
    public static void start() throws IOException {
        System.out.println("服务端启动");
        listen();
    }

    public static void listen() throws IOException {
        System.out.println("监听中");


        // 此处加死循环 是为了让服务器已知监听有没有客户端连接
        while (true){
            // 获取客户端的socket
            Socket socket = serverSocket.accept();
            // 使用线程池执行线程
            pool.execute(new ServerReaderThread(socket));
        }
    }

    // 该方法是一个注册方法
    public static void register(SysUser sysUser,Socket socket) throws IOException, ClassNotFoundException {
        System.out.println("注册");
        // 获取数据库中的所有用户
        FileInputStream fileInputStream = new FileInputStream(file);
        if (fileInputStream.available() > 0) {
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            ArrayList<SysUser> sysUsers = (ArrayList<SysUser>) objectInputStream.readObject();
            for (SysUser user : sysUsers) {
                if (user.getUsername().equals(sysUser.getUsername())) {
                    System.out.println("用户名已存在");
                    OutputStream outputStream = socket.getOutputStream();
                    DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
                    dataOutputStream.writeUTF("用户名已存在");
                    dataOutputStream.flush();
//                    dataOutputStream.close();
                    return;
                }
            }
        }


        // 注册用户
        // 将用户写入数据库 追加模式
        FileOutputStream fileOutputStream = new FileOutputStream(file,true);
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        ArrayList<SysUser> sysUsersRegister = new ArrayList<>();
        sysUsersRegister.add(sysUser);
        objectOutputStream.writeObject(sysUsersRegister);
        System.out.println("注册成功");
        System.out.println(sysUser);
        OutputStream outputStream = socket.getOutputStream();
        DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
        dataOutputStream.writeUTF("注册成功");
        dataOutputStream.flush();
//        dataOutputStream.close();


    }

    // 该方法是一个登录方法
    public static void login(SysUser sysUser,Socket socket) throws IOException, ClassNotFoundException {
        System.out.println("登录");
        // 获取数据库中的所有用户
        FileInputStream fileInputStream = new FileInputStream(file);
        if (fileInputStream.available() > 0) {
            ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
            ArrayList<SysUser> sysUsers = (ArrayList<SysUser>) objectInputStream.readObject();
            for (SysUser user : sysUsers) {
                if (user.getUsername().equals(sysUser.getUsername())&&user.getPassword().equals(sysUser.getPassword())) {
                    System.out.println("登录成功");
                    System.out.println(sysUser);
                    OutputStream outputStream = socket.getOutputStream();
                    DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
                    dataOutputStream.writeUTF("登录成功");
                    dataOutputStream.flush();
//                    dataOutputStream.close();
                }else {
                    System.out.println("用户名或密码错误");
                    OutputStream outputStream = socket.getOutputStream();
                    DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
                    dataOutputStream.writeUTF("用户名或密码错误");
                    dataOutputStream.flush();
//                    dataOutputStream.close();
                }
            }
        }else {
            System.out.println("数据库中没有用户");
            OutputStream outputStream = socket.getOutputStream();
            DataOutputStream dataOutputStream = new DataOutputStream(outputStream);
            dataOutputStream.writeUTF("数据库中没有用户");
            dataOutputStream.flush();
//            dataOutputStream.close();
        }



    }
}

服务器端读取类

  • 本例是一个长连接:一直挂在服务器端,那么服务器端的读取线程中就必须要有一个while 循环 不断读取此长连接的内容
  • 如果不使用本例的方法,而是每次都创建新的socket 连接服务器,那么读取线程中就必须要有一个while 循环就是非必要的,因为每次连接只会发送一次,等待服务器端响应之后,需要关闭此socket,这就是短连接
ServerReaderThread extends Thread {
    private Socket socket;

    public ServerReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            // 最开始这个地方没有死循环,导致客户端只能发送一次请求
            // 这个地方加入死循环 是为了即使是一个request也能一直获得用户的输入
            // 这个地方如果不加入死循环,那么应该建立短连接
            // 也就是说,客户端发送一个请求,都会建立一个新的socket,服务端处理完这个请求之后,返回给客户端结果,客户端处理完结果之后,关闭socket
            while(true){
                // 获取输入流
                InputStream inputStream = socket.getInputStream();
                // 封装输入流为对象输入流
                ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);

                // 读取对象
                Operation operation = (Operation) objectInputStream.readObject();
                // 获取操作
                String operation1 = operation.getOperation();
                // 获取用户
                SysUser sysUser = operation.getSysUser();
                System.out.println("线程方法");
                switch (operation1) {
                    case "register":
                        register(sysUser,socket);
                        break;
                    case "login":
                        login(sysUser,socket);
                        break;
                    default:
                        break;
                }
            }

        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1631933.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

欧科云链:为什么减半对比特币生态的影响正在逐步“减弱”?

出品&#xff5c;OKG Research 作者&#xff5c;Jason Jiang 欧科云链OKLink数据显示&#xff0c;比特币于区块高度840000&#xff08;北京时间2024年4月20日8:09&#xff09;成功完成第四次减半&#xff0c;比特币挖矿奖励正式由6.25BTC减少至3.125BTC。此次减半之后&#x…

RT-Thread之线程管理(线程的基础概念和使用)

文章目录 前言一、RT-Thread线程的概念二、线程的创建与删除2.1用户线程和系统线程2.2线程控制块2.3线程栈2.4入口函数 三、线程的创建和启动3.1线程创建的种类3.2动态创建线程3.3静态创建线程 总结 前言 本篇文章来给大家讲解RT-Thread中的线程管理&#xff0c;线程管理是属于…

GD32E103C8T6 封装LQFP-48 GigaDevice(兆易创新) 单片机

GD32E103C8T6 是由GigaDevice&#xff08;兆易创新&#xff09;公司生产的一款基于ARM Cortex-M4内核的32位MCU&#xff08;微控制器&#xff09;。以下是GD32E103C8T6的一些主要功能和参数介绍&#xff1a; 主要功能&#xff1a; 高性能ARM Cortex-M4内核: 采用120MHz的ARM …

Matlab实现CNN-BiLSTM模型,对一维时序信号进行分类

1、利用Matlab2021b训练CNN-BiLSTM模型&#xff0c;对采集的一维时序信号进行分类二分类或多分类 2、CNN-BiLSTM时序信号多分类执行结果截图 训练进度&#xff1a; 网络分析&#xff1a; 指标变化趋势&#xff1a; 代码下载方式&#xff08;代码含数据集与模型构建&#xff0…

iview 自定义项求和的方法和错误点

这是iview自定义某几项参数合计的方法&#xff0c;其实是蛮简单的&#xff0c;很多人自定义合计的时候&#xff0c;老是会不知道怎么处理除了需要合计的几项的其他项&#xff0c;其实不需要管&#xff0c;不需要合计的项直接返回空就好了&#xff0c;需要的就在计算的里面做key…

MyBatis 核心配置讲解(下)

大家好&#xff0c;我是王有志&#xff0c;一个分享硬核 Java 技术的互金摸鱼侠。 我们书接上回&#xff0c;继续聊 MyBatis 的核心配置&#xff0c;我们今天分享剩下的 5 项核心配置。 不过正式开始前&#xff0c;我会先纠正上一篇文章 MyBatis 核心配置讲解&#xff08;上&…

【链表——数据结构】

文章目录 1.单链表1.定义2.基本操作2.1.不带头结点2.2后插2.3前插2.4删除2.5按位查找2.6按值查找2.7求单链表长度2.8 建表 2.双链表1.初始化2.插入(后插)3.删除(后删)4.遍历 3.循环链表1.循环单链表2.循环双链表3.代码问题 4.静态链表1.简述基本操作的实现1.初始化3.删除某个结…

【AIGC调研系列】Sora级别的国产视频大模型-Vidu

Vidu能够达到Sora级别的标准。Vidu被多个来源认为是国内首个Sora级别的视频大模型[2][3][4]。它采用了团队原创的Diffusion与Transformer融合的架构U-ViT&#xff0c;能够生成长达16秒、分辨率高达1080P的高清视频内容[1][6]。此外&#xff0c;Vidu的一致性、运动幅度都达到了S…

vue2如何创建一个项目?

目录 1. 安装环境&#xff1a; 2. 安装Vue CLI 3. 创建新项目 4. 选择配置 5. 安装依赖并运行 6. 开始开发 7. 构建项目 8. 预览生产环境构建 首先创建一个vue2项目&#xff0c;你可以通过以下步骤进行&#xff1a; 1. 安装环境&#xff1a; 保证自己的电脑已经安装N…

Jmeter Beanshell 设置全局变量

//获取token import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONArray; import java.util.*; import org.apache.jmeter.util.JMeterUtils; //获取可上机机器 String response prev.getResponseDataAsString(); JSONObject responseObect JSONObjec…

rancher/elemental 构建不可变IOS(一)

一、什么是elemental Elemental 是 Rancher 的一个变种&#xff0c;专注于提供一个更轻量级的 Kubernetes 发行版。它旨在提供简化的部署和管理体验&#xff0c;同时保持 Kubernetes 的灵活性和强大功能。Elemental 通常针对较小的部署场景或资源受限的环境&#xff0c;例如测…

PY32F040单片机产品介绍,LQFP封装,带LCD 驱动器

PY32F040单片机搭载了 Arm Cortex-M0内核&#xff0c;最高主频可达72 MHz&#xff0c;专为高性价比、高可靠性的系统而设计&#xff0c;符合消费市场的基本设计需求。可广泛应用于电机控制、手持设备、PC 外设、以及复杂的数字控制应用等领域。 PY32F040片内集成 UART、I2C、S…

Pycharm配深度学习环境所遇到的部分问题

问题1&#xff1a;Anaconda prompt界面安装CUDA出现的问题: 不管是&#xff1a;conda install pytorch torchvision torchaudio cudatoolkit11.3 -c pytorch 还是:pip ****什么的 问题描述&#xff1a;EnvironmentNotWritableError: The current user does not have write p…

手动在Ubuntu22.04上部署LAMP环境

简介 LAMP环境是常用的Web开发环境之一&#xff0c;其中LAMP分别代表Linux、Apache、MySQL和PHP。本文介绍如何在Ubuntu操作系统的ECS实例内部署LAMP环境。 准备工作 该实例必须满足以下条件&#xff1a; 实例已分配公网IP地址或绑定弹性公网IP&#xff08;EIP&#xff09;。…

【Java】java实现文件上传和下载(上传到指定路径/数据库/minio)

目录 上传到指定路径 一、代码层级结构 二、文件上传接口 三、使用postman进行测试&#xff1b; MultipartFile接收前端传递的文件&#xff1a;127.0.0.1:8082/path/uploadFile part接收前端传递的文件&#xff1a;127.0.0.1:8082/path/uploadFileByRequest 接收前端传递…

【存储芯片】CS创世 SD NAND:可以机贴的存储芯片

什么是CS创世 SD NAND呢&#xff1f;很多的朋友一直想知道这个问题。今天精心准备了SD NAND 的一个介绍。其实很多工程师朋友对CS创世 SD NAND有很多称呼。比如&#xff1a;贴片式T卡、贴片式TF卡、贴片式SD卡、可焊接的T卡&#xff0c;可焊接的SD卡&#xff0c;可贴片的TF卡&a…

TikTok引流中海外云手机的实用功能分享

在当下&#xff0c;TikTok已成为全球范围内最受欢迎的社交媒体平台之一&#xff0c;拥有着庞大的用户群体和潜在的商业机会。为了在TikTok上实现更好的引流效果&#xff0c;利用海外云手机成为了一个明智的选择。接下来&#xff0c;我们将深入探讨海外云手机的功能以及它如何助…

LLM优化:开源星火13B显卡及内存占用优化

1. 背景 本qiang~这两天接了一个任务&#xff0c;部署几个开源的模型&#xff0c;并且将本地经过全量微调的模型与开源模型做一个效果对比。 部署的开源模型包括&#xff1a;星火13B&#xff0c;Baichuan2-13B, ChatGLM6B等 其他两个模型基于transformers架构封装&#xff0…

创建基于时间的 UUID

概述 在本文中&#xff0c;我们将会 对 UUIDs 和基于时间的 UUIDs&#xff08;time-based UUIDs&#xff09; 进行一些探讨。 当我们在对基于时间的 UUIDs 进行选择的时候&#xff0c;总会遇到一些好的方面和不好的方面&#xff0c;如何进行选择&#xff0c;也是我们将要简要…

代码+视频,R语言绘制生存分析模型的时间依赖(相关)性roc曲线和时间依赖(相关)性cindex曲线

ROC曲线分析是用于评估一个因素预测能力的手段&#xff0c;是可以用于连续型变量分组的方法。在生存分析中&#xff0c;疾病状态和因素取值均会随时间发生变化。而标准的ROC曲线分析将个体的疾病状态和因素取值视作固定值&#xff0c;未将时间因素考虑在分析之中。在这种情况下…