RPC模式

简介: RPC模式

RPC模式


 

一、概念:

rpc模式:即客户端、服务端之间的信息交流模式,

客户端通过发送请求数据包给服务端,

服务端接收到数据包(拆解数据包),进行业务处理后,返回一个处理过的数据包给客户端,

然后客户端再进行操作。

 

二、流程图

17.png

 

三、举例:

❀ 客户端界面(登录界面)

import Client.net.Client;
import Common.entity.BizType;
import Common.entity.User;
import Common.util.SysDto;
/**
 * 登录界面类
 * @author Huangyujun
*/
public class LoginFrame extends JFrame{//登录客户端
    Client client = null;
   //.....界面的东西省略....../**
     * 为登录按纽添加事件(~核心功能~~~)
     */
    private void loginEvent() {
     //btnLogin: 登录按钮
        btnLogin.addActionListener(new ActionListener() {  
            @Override
            public void actionPerformed(ActionEvent e) {
                //构建客户端
                client = new Client("localhost", 8888);
                //构建登录业务的DTO(DTO 是数据包对象)
                SysDto sysDto = new SysDto(BizType.登录);
          //account和 password 是登录界面的账号和密码输入框 
                String account = txtLoginName.getText();
                String password = txtLoginPwd.getText();
                sysDto.setUser(new User(account, password));
                //发送
                SysDto dto = null;
                try {    
                        dto = client.sendAndReadDto(sysDto);
                } catch (ClassNotFoundException | IOException e1) {
                    e1.printStackTrace();
                }
                //若登录成功后,进入聊天界面
                if(dto.getBizType().equals(BizType.登录成功)) {
                    //打印从服务端处理后的登录用户信息
                    System.out.println("从服务端处理后的登录用户信息: ");
                    System.out.println("从服务端返回用户账号:" + dto.getUser().getAccount());
                    System.out.println("从服务端返回用户密码:" + dto.getUser().getPassword());
                }
            }
        });
    }
}

 

❀ 客户端

package Client.net;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.concurrent.TimeUnit;
import Common.entity.BizType;
import Common.util.SysDto;
/**
 * 客户端
 * @author Huangyujun
 *
*/
public class Client {
    private String host;
    private int port;
    private Socket client;
    private ObjectOutputStream objOutStream;
    private ObjectInputStream objInStream;
    private boolean isRunning;
    //构造方法
    public Client(String host, int port) {
        this.host = host;
        this.port = port;
        isRunning = true;
        try {
            client = new Socket(host, port);
            objOutStream = new ObjectOutputStream(client.getOutputStream());
            objInStream = new ObjectInputStream(client.getInputStream());
        } catch (IOException e) {
            e.printStackTrace();
        }    
    }
    /**
     * 发送DTO
     * @param sysDto
     * @throws IOException 
     */
    public void sendDto(SysDto sysDto) throws IOException {
        objOutStream.writeObject(sysDto);
        //推流
        objOutStream.flush();
    }
    /**
     * 接收DTO
     * @return
     * @throws ClassNotFoundException
     * @throws IOException
     */
    public SysDto readDto() throws ClassNotFoundException, IOException {
        Object data = objInStream.readObject();
        return (SysDto) data;
    }
    /**
     * 发送并接收DTO
     * @param sysDto
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public SysDto sendAndReadDto(SysDto sysDto) throws IOException, ClassNotFoundException {
        sendDto(sysDto);
        return readDto();
    }
    /**
     * 关闭操作方法
     */
    public void close(SysDto sysDto) {
        if(sysDto.getBizType().equals(BizType.退出)) {
            //发送退出数据包给服务器,让服务器断开处理客户端的客户端任务
            try {
                sendDto(sysDto);
            } catch (IOException e1) {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            //退出:关闭各种流和Socket
            try {
                //休息一下,避免与更新界面冲突
                TimeUnit.MILLISECONDS.sleep(5000);
                objInStream.close();
                objOutStream.close();
                client.close();            
            } catch (IOException | InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }
    public Socket getClient() {
        return client;
    }
    public void setClient(Socket client) {
        this.client = client;
    }
    public boolean isRunning() {
        return isRunning;
    }
    public void setRunning(boolean isRunning) {
        this.isRunning = isRunning;
    }
}

 

❀ 数据包

package Common.util;
import java.io.Serializable;
import Common.entity.BizType;
import Common.entity.User;
/**
 * 数据传输对象,也需要在网络上传输,实现序列化
 * @author Huangyujun
 *
*/
public class SysDto implements Serializable {
    private static final long serialVersonUID = 2;
    private BizType bizType;        //数据传输对象类型
    //先考虑登录业务所需传输的数据对象
    private User user;
  //构造方法
    public SysDto(BizType bizType) {
        this.bizType = bizType;
    }
    public BizType getBizType() {
        return bizType;
    }
    public void setBizType(BizType bizType) {
        this.bizType = bizType;
    }
    public User getUser() {
        return user;
    }
    public void setUser(User user) {
        this.user = user;
    }
}

 

❀ 服务端

package ServerNet;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import Common.entity.User;
import Common.util.SysDto;
/**
 * 服务端
 * @author Huangyujun
 *
*/
public class Server {
    private int port;                    //端口
    private boolean isRunning;            //运行状态
    private ServerSocket serverSocket;    //服务器
    /** 客户端任务集合 */
    private static List<SocketHandler> listHandler = null;
    //构造方法
    public Server(int port) {
        this.port = port;
        isRunning = true;
        listHandler = new ArrayList<SocketHandler>();
    }
    /**
     * 启动方法
     */
    public void start() {
        //构建服务端,并连接
        serverSocket = null;
        try {
            serverSocket = new ServerSocket(port);
            System.out.println("服务端已经连接,正在监听端口:" + port);
            //循环不断地监听客户端
            while(isRunning) {
                Socket client = serverSocket.accept();
                //创建客户端任务处理客户端业务请求,将当前活跃的客户端传入
            SocketHandler socketHandler = new SocketHandler(client);
            //listHandler 添加socketHandler 客户端任务
                listHandler.add(socketHandler);
                //启动客户端任务线程
                new Thread(socketHandler).start();    
            }    
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    public ServerSocket getServerSocket() {
        return serverSocket;
    }
    public void setServerSocket(ServerSocket serverSocket) {
        this.serverSocket = serverSocket;
    }
    public List<SocketHandler> getListHandler() {
        return listHandler;
    }
    }

 

❀ 客户端处理器

package ServerNet;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import Common.entity.BizType;
import Common.entity.User;
import Common.util.SysDto;
import ServerBiz.ServerBiz;
/**
 * 客户端任务类
 * @author Huangyujun
 *
*/
public class SocketHandler implements Runnable{
    private Socket client;
    private boolean isRunning;
    private ObjectInputStream objInStream;
    private ObjectOutputStream objOutStream;
    /** 服务端业务处理对象 */
    private ServerBiz serverBiz;
    //当前用户~登录完成就有啦
    private User loginUsers;
    //构造方法
    public SocketHandler(Socket client) {
     //当前客户端
        this.client = client;
        serverBiz = new ServerBiz();
        isRunning = true;
        //获得输入对象流、输出对象流
        objInStream = null;
        try {
            objInStream = new ObjectInputStream(client.getInputStream());
            objOutStream = new ObjectOutputStream(client.getOutputStream());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }    
    }
    @Override
    public void run() {
        //先不断地接收客户端传递的业务数据
        Object data = null;
        try {
            while((data = objInStream.readObject()) != null){
                //1,先判断数据属于什么业务
                if(!(data instanceof SysDto)) {
                    System.out.println("未知业务类型,无法处理!");
                }else {
                    //2,进行类型转换
                    SysDto sysDto = (SysDto) data;
                    //3,调用业务类的方法,处理返回处理后的数据包
                    SysDto dto = serverBiz.dealWithType(sysDto);
               if(dto.getBizType().equals(BizType.登录成功)) {
                        this.loginUsers = dto.getUser();
                    }
                    //4,将处理后得到的数据包写回给客户端
               objOutStream.writeObject(dto);
               //5,推流
                    objOutStream.flush();
                    if(dto.getBizType().equals(BizType.退出成功)) {
                        //休息10秒钟
                        Thread.sleep(10000);
                        //设置客户端任务状态为false,
                        isRunning = false;
                        //关闭各种流和Socket
                        objOutStream.close();
                        objInStream.close();
                        client.close();
                        break;
                    }                
                }
            }
        } catch (ClassNotFoundException | IOException | InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
public boolean isRunning() {
        return isRunning;
    }
    public User getLoginUsers() {
        return loginUsers;
    }
}

 

❀ 服务业务类

网络异常,图片无法展示
|

package ServerBiz;


import java.io.IOException;

import java.net.Socket;

import java.util.ArrayList;

import java.util.List;


import Common.entity.BizType;

import Common.entity.Message;

import Common.entity.User;

import Common.util.SysDto;

import ServerNet.Server;

import ServerNet.SocketHandler;


/**

* 服务端业务处理类,把传进来的Dto进行处理后返回

* @author Huangyujun

*

*/

publicclass ServerBiz {

   //工厂方法

   public SysDto dealWithType(SysDto sysDto) throws IOException {

       switch(sysDto.getBizType()) {

           case 登录:

               return doLogin(sysDto);

      case 退出:

               return doExit(sysDto);

       }

       returnnull;

   }

/**

    * 登录业务

    * @param sysDto

    * @return

    */

   private SysDto doLogin(SysDto sysDto) {

       //1,验证密码、账号是否正确(没有数据库省略)

       //2,从数据库获取该用户信息

       //3,设置sysDto类型为登录成功

       //4,返回设置了用户信息的sysDto

       String account = sysDto.getUser().getAccount();

       String password = sysDto.getUser().getPassword();

       User user = new User(account, password);

       System.out.println("当前从客户端传递来的用户账号是:" + account + " 密码是:" + password);

       //设置业务类型为登录成功

       sysDto.setBizType(BizType.登录成功);

       System.out.println("当前在线人数:" +Server.getOnlineHandler().size());

       //设置DTO的用户信息

package ServerBiz;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;
import Common.entity.BizType;
import Common.entity.Message;
import Common.entity.User;
import Common.util.SysDto;
import ServerNet.Server;
import ServerNet.SocketHandler;
/**
 * 服务端业务处理类,把传进来的Dto进行处理后返回
 * @author Huangyujun
 *
*/
public class ServerBiz {
    //工厂方法
    public SysDto dealWithType(SysDto sysDto) throws IOException {
        switch(sysDto.getBizType()) {
            case 登录:
                return doLogin(sysDto);
       case 退出:
                return doExit(sysDto);
        }
        return null;
    }
/**
     * 登录业务
     * @param sysDto
     * @return
     */
    private SysDto doLogin(SysDto sysDto) {
        //1,验证密码、账号是否正确(没有数据库省略)
        //2,从数据库获取该用户信息
        //3,设置sysDto类型为登录成功
        //4,返回设置了用户信息的sysDto
        String account = sysDto.getUser().getAccount();
        String password = sysDto.getUser().getPassword();
        User user = new User(account, password);
        System.out.println("当前从客户端传递来的用户账号是:" + account + " 密码是:" + password);
        //设置业务类型为登录成功
        sysDto.setBizType(BizType.登录成功);
        System.out.println("当前在线人数:" +Server.getOnlineHandler().size());
        //设置DTO的用户信息
        sysDto.setUser(user);
        return sysDto;
    }
}
目录
相关文章
|
8天前
|
消息中间件
RabbitMQ的 RPC 消息模式你会了吗?
【9月更文挑战第11天】RabbitMQ 的 RPC(远程过程调用)消息模式允许客户端向服务器发送请求并接收响应。其基本原理包括:1) 客户端发送请求,创建回调队列并设置关联标识符;2) 服务器接收请求并发送响应至回调队列;3) 客户端根据关联标识符接收并匹配响应。实现步骤涵盖客户端和服务器的连接、信道创建及请求处理。注意事项包括关联标识符唯一性、回调队列管理、错误处理及性能考虑。RPC 模式适用于构建可靠的分布式应用程序,但需根据需求调整优化。
|
3月前
|
存储 C++
gRPC 四模式之 双向流RPC模式
gRPC 四模式之 双向流RPC模式
95 0
|
3月前
|
安全 C++
gRPC 四模式之 客户端流RPC模式
gRPC 四模式之 客户端流RPC模式
40 0
|
3月前
|
C++
gRPC 四模式之 服务器端流RPC模式
gRPC 四模式之 服务器端流RPC模式
73 0
|
3月前
|
JSON API 数据格式
gRPC 四模式之 一元RPC模式
gRPC 四模式之 一元RPC模式
32 0
|
4月前
|
消息中间件 Java 数据库连接
实时计算 Flink版产品使用合集之将sdkMode从rpc模式改为jdbc模式后,table.exec.mini-batch.enabled参数还生效吗
实时计算Flink版作为一种强大的流处理和批处理统一的计算框架,广泛应用于各种需要实时数据处理和分析的场景。实时计算Flink版通常结合SQL接口、DataStream API、以及与上下游数据源和存储系统的丰富连接器,提供了一套全面的解决方案,以应对各种实时计算需求。其低延迟、高吞吐、容错性强的特点,使其成为众多企业和组织实时数据处理首选的技术平台。以下是实时计算Flink版的一些典型使用合集。
|
消息中间件 存储 Dubbo
真的好用吗?鲜有人提的 RabbitMQ-RPC模式
真的好用吗?鲜有人提的 RabbitMQ-RPC模式
159 0
|
消息中间件 存储 设计模式
Seata 高性能 RPC 通信的实现- 巧用 reactor 模式
reactor 模式是一种事件驱动的应用层 I/O 处理模式,基于分而治之和事件驱动的思想,致力于构建一个高性能的可伸缩的 I/O 处理模式
170 0
|
XML 消息中间件 数据格式
[原创]AMQP-RabbitMQ/6/RPC模式/关注消息处理结果
[原创]AMQP-RabbitMQ/6/RPC模式/关注消息处理结果
[原创]AMQP-RabbitMQ/6/RPC模式/关注消息处理结果
|
监控 前端开发 Java
Spring Cloud实战小贴士:Feign的继承特性(伪RPC模式)
Spring Cloud实战小贴士:Feign的继承特性(伪RPC模式)
186 0