3

本文主要小结一下通信协议设计的要点。

考虑点

1、采用什么传输协议

TCP还是UDP还是HTTP,即在哪一层进行传输

2、采用什么传输格式

即编码协议及序列化方式

(1)采用什么字符集编码/解码
(2)单个字符到字节的顺序(big-endian还是little-endian)
(3)多个字符的分隔方式(采用分隔符还是定长方式,还是带字符长度的信息)

3、消息的设计

(1)消息头

    定长,包括消息版本号(1字节)、消息序列号(4字节整型)、消息数据长度(可设计为包含消息类型块的长度,或者仅仅是消息体的长度)、消息延续标志(是/否,消息超长处理用)

(2)消息类型块

    请求类型:响应类型、消息体长度
    回复类型:响应类型、消息体长度、错误信息(错误号、错误类型、错误内容)、消息处理标志

(3)消息体

实例

Message对象

public class XMessage {
    private EncodeEnum encode;
    private int length;
    private String content;
    public void writeUtf8(String msg){
        this.encode = EncodeEnum.UTF8;
        this.content = msg;
        this.length = msg.length();
    }
    public EncodeEnum getEncode() {
        return encode;
    }
    public void setEncode(EncodeEnum encode) {
        this.encode = encode;
    }
    public int getLength() {
        return length;
    }
    public void setLength(int length) {
        this.length = length;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    @Override
    public String toString() {
        return "XMessage{" +
                "encode=" + encode +
                ", length=" + length +
                ", content='" + content + '\'' +
                '}';
    }
}

编解码

public class XProtocol {
    public static void encode(OutputStream outputStream,XMessage xMessage) throws IOException {
        //write encoding
        DataOutputStream dout = new DataOutputStream(outputStream);
        dout.writeInt(xMessage.getEncode().ordinal());
        //write content length
        dout.writeInt(xMessage.getLength());
        //write content
        dout.write(xMessage.getContent().getBytes(xMessage.getEncode().desc));
    }
    public static XMessage decode(InputStream input) throws IOException {
        DataInputStream din = new DataInputStream(input);
        XMessage xMessage = new XMessage();
        //get encoding
        int encode = din.readInt();
        EncodeEnum encodeEnum = EncodeEnum.getByIdx(encode);
        xMessage.setEncode(encodeEnum);
        //get content length
        int length = din.readInt();
        xMessage.setLength(length);
        //get content
        byte[] data = new byte[length];
        din.read(data);
        String content = new String(data,encodeEnum.desc);
        xMessage.setContent(content);
        return xMessage;
    }
}

Server端

public class XServer {
    public static void main(String[] args) throws IOException {
        ServerSocket server = new ServerSocket(9090);
        System.out.println("server running");
        while(true){
            Socket socket = server.accept();
            InputStream inputStream = socket.getInputStream();
            XMessage inMsg =XProtocol.decode(inputStream);
            System.out.println("receive from client:"+inMsg);
            OutputStream outputStream = socket.getOutputStream();
            XMessage outMsg = new XMessage();
            outMsg.writeUtf8("got our msg");
            XProtocol.encode(outputStream,outMsg);
            socket.close();
        }
    }
}

Client端

public class XClient {
    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1",9090);
        OutputStream out = socket.getOutputStream();
        XMessage outMsg = new XMessage();
        outMsg.writeUtf8("hello server");
        XProtocol.encode(out,outMsg);
        InputStream inputStream = socket.getInputStream();
        XMessage inMsg = XProtocol.decode(inputStream);
        System.out.println("receive from server:"+inMsg);
    }
}

本工程github

其他

待补充


codecraft
11.9k 声望2k 粉丝

当一个代码的工匠回首往事时,不因虚度年华而悔恨,也不因碌碌无为而羞愧,这样,当他老的时候,可以很自豪告诉世人,我曾经将代码注入生命去打造互联网的浪潮之巅,那是个很疯狂的时代,我在一波波的浪潮上留下...


引用和评论

0 条评论