当前位置: 首页 > article >正文

【MyDB】7-客户端服务端通信之1-服务端客户端通信实现前言

【MyDB】7-客户端服务端通信之1-服务端客户端通信实现前言

  • 前言
    • C/S 通信

前言

MYDB 被设计为 C/S 结构,类似于 MySQL。支持启动一个服务器,并有多个客户端去连接,通过 socket 通信,执行 SQL 返回结果。

C/S 通信

MYDB 使用了一种特殊的二进制格式,用于客户端和服务端通信。当然如果嫌麻烦的话,其实直接用明文也不是不可以。

传输的最基本结构,是 Package:

public class Package {
    byte[] data;
    Exception err;
}

每个 Package 在发送前,由 Encoder 编码为字节数组,在对方收到后同样会由 Encoder 解码成 Package 对象。编码和解码的规则如下:

[Flag][data]

若 flag 为 0,表示发送的是数据,那么 data 即为这份数据本身;如果 flag 为 1,表示发送的是错误,data 是 Exception.getMessage() 的错误提示信息。如下:

public class Encoder {
    public byte[] encode(Package pkg) {
        if(pkg.getErr() != null) {
            Exception err = pkg.getErr();
            String msg = "Intern server error!";
            if(err.getMessage() != null) {
                msg = err.getMessage();
            }
            return Bytes.concat(new byte[]{1}, msg.getBytes());
        } else {
            return Bytes.concat(new byte[]{0}, pkg.getData());
        }
    }

    public Package decode(byte[] data) throws Exception {
        if(data.length < 1) {
            throw Error.InvalidPkgDataException;
        }
        if(data[0] == 0) {
            return new Package(Arrays.copyOfRange(data, 1, data.length), null);
        } else if(data[0] == 1) {
            return new Package(null, new RuntimeException(new String(Arrays.copyOfRange(data, 1, data.length))));
        } else {
            throw Error.InvalidPkgDataException;
        }
    }
}

编码之后的信息会通过 Transporter 类,写入输出流发送出去。为了避免特殊字符造成问题,这里会将数据转成十六进制字符串(Hex String),并为信息末尾加上换行符。这样在发送和接收数据时,就可以很简单地使用 BufferedReader 和 Writer 来直接按行读写了。

public class Transporter {
    private Socket socket;
    private BufferedReader reader;
    private BufferedWriter writer;

    public Transporter(Socket socket) throws IOException {
        this.socket = socket;
        this.reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
        this.writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
    }

    public void send(byte[] data) throws Exception {
        String raw = hexEncode(data);
        writer.write(raw);
        writer.flush();
    }

    public byte[] receive() throws Exception {
        String line = reader.readLine();
        if(line == null) {
            close();
        }
        return hexDecode(line);
    }

    public void close() throws IOException {
        writer.close();
        reader.close();
        socket.close();
    }

    private String hexEncode(byte[] buf) {
        return Hex.encodeHexString(buf, true)+"n";
    }

    private byte[] hexDecode(String buf) throws DecoderException {
        return Hex.decodeHex(buf);
    }
}

Packager 则是 Encoder 和 Transporter 的结合体,直接对外提供 send 和 receive 方法:

public class Packager {
    private Transporter transpoter;
    private Encoder encoder;

    public Packager(Transporter transpoter, Encoder encoder) {
        this.transpoter = transpoter;
        this.encoder = encoder;
    }

    public void send(Package pkg) throws Exception {
        byte[] data = encoder.encode(pkg);
        transpoter.send(data);
    }

    public Package receive() throws Exception {
        byte[] data = transpoter.receive();
        return encoder.decode(data);
    }

    public void close() throws Exception {
        transpoter.close();
    }
}

http://www.kler.cn/a/593604.html

相关文章:

  • deque
  • sql批量修改字段某一指定部分+修改重复编号
  • java TCP UDP 客户端访问例子和对比差异
  • 九、JavaScript作用域、预解析
  • 2025年高校辅导员考试题库及答案
  • numpy学习笔记9:numpy的广播机制详细解释
  • 【Transformer】架构:解锁自然语言处理的无限可能
  • 关于金融开发领域的一些专业知识总结
  • 第十三章,L2TP VPN
  • XSS漏洞靶场练习
  • 成都国际数字影像产业园,文创产业运营新典范深度解析​
  • win10 如何用我的笔记本 接网线 远程控制 台式机
  • Python个人学习笔记(17):模块(sys、picklejson)
  • 4.6--入门知识扫盲,路径追踪与路由误导:Tracert攻击 vs ICMP重定向攻击(包你看一遍全记住)
  • iPaaS集成平台中的API可视化编排能给企业带来什么作用
  • Bilve 搭建手册
  • 解析Collections工具类主要功能
  • Execution failed for task ‘:path_provider_android:compileDebugJavaWithJavac‘.
  • PyTorch分布式训练中各节点如何通信
  • 第1次课枚举算法