Okio usage analysis

Keywords: socket Java Retrofit OkHttp

Recently, in researching the concrete implementation of retrofit, retrofit uses okhttp,okhttp uses Okio,so I want to start with the bottom Okio. And I haven't taken a serious look at the IO block of java, so I take this opportunity to learn about io.

This article is about Okio. Next, I should write about okhttp and retrofit. There are a lot of articles about these three frameworks on the Internet, why should we write them by ourselves? Because other people's articles read more, after all, they don't write one by themselves. They always look at other people's articles from the beginning. After reading, they don't have a kind of penetrating feeling. They seem to understand the whole framework or not, and they are almost forgotten in two days, so many things are self-explanatory. It's necessary to write it down.

Based on the analysis of okio-1.9.0, different versions may differ. If there are any mistakes, please leave a message to correct them.

Look at a picture first (this is not a strict UML diagram, it's a draft).

Okio's source code is actually not much, look at a total of more than 20 classes, most of which are not very long. There are only a few core classes in these classes, which constitute the skeleton of okio. Here are some core classes:
Okio: Provides a way to generate Sink and Source
Sink: Interface class, functionally corresponding to OutputStream
Source: Interface class, functionally corresponding to InputStream
BufferedSink: The interface class inherits from Sink and has a Buffer ink inside.
BufferedSource: The interface class inherits from Source and has a Buffer Source inside.
Buffer: The final implementation class of BufferedSink and BufferedSource, which implements the caching function, has a Segment list inside.
Segment: There's a byte array in it. It controls the position of reading and writing through pos,limit (where to start reading and where to start writing from byte []), next, prev to navigate to the front or back Segment list structure.

Here's a simple way to use it

socket = new Socket("127.0.0.1", 8080);
InputStream inputStream = socket.getInputStream();
OutputStream outputStream = socket.getOutputStream();
BufferedSource source = Okio.buffer(Okio.source(inputStream));
BufferedSink sink = Okio.buffer(Okio.sink(outputStream));

Usually we use socket, sometimes we call InputStream and OutputStream directly to read and write data. After using Okio, we can construct Source and Sink through InputStream and OutputStream, and then call Source and Ink to provide methods to read and write data. Source and Link provide a large number of methods to read and write data, which can support byte stream and character stream, while using Buffer to improve the efficiency of reading and writing.
Writing here, I find that I haven't written out where okio is really good and how to achieve it. This oneself haven't read very well for the time being, read later and write this part again.

The following is an example of communication through socket, which is divided into client and server.
Server.java

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.Charset;

import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;

/**
 * Created by lee on 2017/1/24.
 */

public class Server {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        try {
            serverSocket = new ServerSocket(8080);
            while (true) {
                Socket socket = serverSocket.accept();
                handleClientSocket(socket);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (serverSocket != null) {
                try {
                    serverSocket.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void handleClientSocket(Socket socket) {
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    while (true) {
                        BufferedSource source = Okio.buffer(Okio.source(socket));
                        BufferedSink sink = Okio.buffer(Okio.sink(socket));
                        int length = source.readInt();
                        String message = source.readString(length, Charset.forName("utf-8"));
                        System.out.println("length is: " + length + " , message is : " + message);
                        if("error exit".equals(message)){
                            break;
                        }
                        String responseMsg = getResponseAccordMsg(message);
                        if (responseMsg != null) {
                            int respLength = responseMsg.getBytes().length;
                            sink.writeInt(respLength);
                            sink.writeString(responseMsg, Charset.forName("utf-8"));
                            sink.flush();
                        }
                        if("error exit".equals(responseMsg)){
                            break;
                        }
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }finally {
                    if(socket!=null){
                        try {
                            socket.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }

            }
        });
        thread.start();
    }

    private static String getResponseAccordMsg(String msg) {
        String result = "";
        if (msg != null && msg.length() > 0) {
            if (msg.equals("hello")) {
                result = "hello";
            } else if (msg.equals("nice to meet you")) {
                result = "nice to meet you too";
            } else if (msg.equals("see you")) {
                result = "see you next time";
            }
        }
        if (result.length() == 0) {
            result = "error exit";
        }
        return result;
    }
}

client code
OkioClient.java

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.nio.charset.Charset;

import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;

/**
 * Created by lee on 2017/1/24.
 */

public class OkioClient {

    public static void main(String[] args) {
        Socket socket = null;
        try {
            socket = new Socket("127.0.0.1", 8080);
            InputStream inputStream = socket.getInputStream();
            OutputStream outputStream = socket.getOutputStream();
            BufferedSource source = Okio.buffer(Okio.source(inputStream));
            BufferedSink sink = Okio.buffer(Okio.sink(outputStream));
            writeMsg(sink, "hello");
            while (true) {
                int length = source.readInt();
                String message = source.readString(length, Charset.forName("utf-8"));
                System.out.println("length is: "+length+" , message is : "+message);
                if ("error exit".equals(message)) {
                    break;
                }
                String respMsg = getResponseAccordMsg(message);
                writeMsg(sink, respMsg);
                if ("error exit".equals(respMsg)) {
                    break;
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (socket != null) {
                try {
                    socket.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private static void writeMsg(BufferedSink sink, String msg) {
        try {
            int msgLength = msg.getBytes().length;
            sink.writeInt(msgLength);
            sink.writeString(msg, Charset.forName("utf-8"));
            sink.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private static String getResponseAccordMsg(String msg) {
        String result = "";
        if (msg != null && msg.length() > 0) {
            if (msg.equals("hello")) {
                result = "nice to meet you";
            } else if (msg.equals("nice to meet you too")) {
                result = "see you";
            }
        }
        if (result.length() == 0) {
            result = "error exit";
        }
        return result;
    }
}

Posted by werty37 on Sat, 23 Mar 2019 03:15:55 -0700