封裝socket的通信協議完成文本通信

封裝socket的通信協議完成文本通信

socket是典型的cs架構,由於client端通過OutputStream發送消息,server端通過InputStream接收消息。一般發送本文信息都是一條條發出去的,接收端無法得知每條消息的邊界。所以對協議封裝一下完成文本信息逐條發送並在服務端實時解析。
首先約定好協議的標準

public class Protocol {
    public static final int OPEN = 1;
    public static final int TALK = 2;
    public static final int QUIT = 3;
}

socket客戶端的代碼

public class EchoClient implements Closeable {
    private String host;
    private int port;
    private Socket client;


    public EchoClient(String host, int port) {
        this.host = host;
        this.port = port;
        try {
            client = new Socket(host, port);
            open(client);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void open(Socket client) {
        try {
            OutputStream outputStream = client.getOutputStream();
            DataOutputStream write = new DataOutputStream(outputStream);
            write.write(Protocol.OPEN);
            write.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void sendMessage(String message) {
        try {
            byte[] data = message.getBytes("UTF-8");
            OutputStream outputStream = client.getOutputStream();
            DataOutputStream write = new DataOutputStream(outputStream);
            write.writeByte(Protocol.TALK);
            write.writeInt(data.length);
            write.write(data);
            write.flush();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void close() throws IOException {
        OutputStream outputStream = null;
        try {
            outputStream = client.getOutputStream();
            DataOutputStream write = new DataOutputStream(outputStream);
            write.write(Protocol.QUIT);
            write.flush();
            write.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (outputStream != null) {
                try {
                    outputStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        client.close();
    }

    public static void main(String[] args) {
        try (EchoClient client = new EchoClient("localhost", 55533)) {
            for (int i = 0; i < 5000; i++) {
                client.sendMessage(String.format("hello world %s", i));
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

socket服務端的代碼

public class EchoServer implements Closeable, Runnable {
    private int port;
    private ServerSocket server;
    private boolean RUNNINGSTATE = false;

    public EchoServer(int port) {
        this.port = port;
        try {
            server = new ServerSocket(port);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void listener() {
        Socket client = null;
        try {
            client = server.accept();
        } catch (IOException e) {
            e.printStackTrace();
        }
        accept(client);
    }

    @Override
    public void run() {
        listener();
    }

    public void onOpen(Socket socket) {
        RUNNINGSTATE = true;
        System.out.println(String.format("新連接%s進來了", socket.getInetAddress()));
    }

    public void onClose(Socket socket) {
        System.out.println(String.format("客戶端%s退出連接", socket.getInetAddress()));
    }

    public void handle(String message) {
        System.out.println(message);
    }

    public void accept(Socket socket) {
        try {
            InputStream inputStream = socket.getInputStream();
            BufferedInputStream read = new BufferedInputStream(inputStream);
            int type = 0;
            while ((type = read.read()) != -1) {
                switch (type) {
                    case Protocol.OPEN:
                        onOpen(socket);
                        break;
                    case Protocol.QUIT:
                        onClose(socket);
                        break;
                    case Protocol.TALK:
                        byte[] buffer = new byte[1024];
                        int len = readInt(read);
                        int offset = 0;
                        StringBuilder sb = new StringBuilder();
                        while (len > 0 && (offset = read.read(buffer, 0, len < buffer.length ? len : buffer.length)) != -1) {
                            sb.append(new String(buffer, 0, offset, "UTF-8"));
                            len -= offset;
                        }
                        handle(sb.toString());
                }
            }
            read.close();
            inputStream.close();
            socket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public final int readInt(InputStream in) throws IOException {
        int ch1 = in.read();
        int ch2 = in.read();
        int ch3 = in.read();
        int ch4 = in.read();
        if ((ch1 | ch2 | ch3 | ch4) < 0)
            throw new EOFException();
        return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
    }

    public boolean isRUNNINGSTATE() {
        return RUNNINGSTATE;
    }

    public static void main(String[] args) {
        EchoServer echoServer = new EchoServer(55533);
        echoServer.run();
    }

    @Override
    public void close() throws IOException {
        server.close();
    }
}

然後啓動服務端和客戶端即可完成消息的發送和接受

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章