Browse Source

smart-socket (#3907)

smart-socket
三刀 7 years ago
parent
commit
55f5355c8f

+ 23 - 0
frameworks/Java/smart-socket/README.md

@@ -0,0 +1,23 @@
+# smart-socket Benchmarking Test
+
+
+This is the smart-socket portion of a [benchmarking test suite](../) comparing a variety of web development platforms.
+
+### JSON Encoding Test
+* [JSON test source](src/main/java/org/smartboot/http/HttpBootstrap.java)
+* [Plaintext test source](src/main/java/org/smartboot/http/HttpBootstrap.java)
+
+## Versions
+
+* [Java OpenJDK 1.8](http://openjdk.java.net/)
+* [smart-socket 1.3.12](https://github.com/smartboot/smart-socket)
+
+## Test URLs
+
+### JSON Encoding Test
+
+    http://localhost:8080/json
+    
+### Plaintext Encoding Test
+
+    http://localhost:8080/plaintext

+ 24 - 0
frameworks/Java/smart-socket/benchmark_config.json

@@ -0,0 +1,24 @@
+{
+  "framework": "smart-socket",
+  "tests": [{
+    "default": {
+      "json_url": "/json",
+      "plaintext_url": "/plaintext",
+      "port": 8080,
+      "approach": "Realistic",
+      "classification": "Platform",
+      "database": "None",
+      "framework": "smart-socket",
+      "language": "Java",
+      "flavor": "None",
+      "orm": "Raw",
+      "platform": "smartboot",
+      "webserver": "None",
+      "os": "Linux",
+      "database_os": "Linux",
+      "display_name": "smart-socket",
+      "notes": "",
+      "versus": "smart-socket"
+    }
+  }]
+}

+ 75 - 0
frameworks/Java/smart-socket/pom.xml

@@ -0,0 +1,75 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>org.smartboot.socket</groupId>
+    <artifactId>smart-socket-benchmark</artifactId>
+    <version>1.0</version>
+    <packaging>jar</packaging>
+    <parent>
+        <artifactId>smart-socket-parent</artifactId>
+        <groupId>org.smartboot.socket</groupId>
+        <version>1.3.12</version>
+    </parent>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <commons.lang.version>2.6</commons.lang.version>
+    </properties>
+    <dependencies>
+        <dependency>
+            <groupId>org.smartboot.socket</groupId>
+            <artifactId>aio-core</artifactId>
+        </dependency>
+    </dependencies>
+    <repositories>
+        <repository>
+            <id>central</id>
+            <name>Central Repository</name>
+            <url>https://repo.maven.apache.org/maven2</url>
+        </repository>
+    </repositories>
+    <pluginRepositories>
+        <pluginRepository>
+            <id>central</id>
+            <name>Central Repository</name>
+            <url>https://repo.maven.apache.org/maven2</url>
+        </pluginRepository>
+    </pluginRepositories>
+    <build>
+        <plugins>
+
+            <plugin>
+                <inherited>true</inherited>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.7.0</version>
+                <configuration>
+                    <source>1.8</source>
+                    <target>1.8</target>
+                    <optimize>true</optimize>
+                    <debug>false</debug>
+                </configuration>
+            </plugin>
+
+            <plugin>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>3.1.0</version>
+                <configuration>
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
+                </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+
+        </plugins>
+    </build>
+</project>

+ 10 - 0
frameworks/Java/smart-socket/smart-socket.dockerfile

@@ -0,0 +1,10 @@
+FROM maven:3.5.3-jdk-10-slim as maven
+WORKDIR /smart-socket
+COPY pom.xml pom.xml
+COPY src src
+RUN mvn compile assembly:single
+
+FROM openjdk:10-jre-slim
+WORKDIR /smart-socket
+COPY --from=maven /smart-socket/target/smart-socket-benchmark-1.0-jar-with-dependencies.jar app.jar
+CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC", "-XX:+AggressiveOpts", "-cp", "app.jar", "org.smartboot.http.HttpBootstrap"]

+ 17 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/BufferRange.java

@@ -0,0 +1,17 @@
+package org.smartboot.http;
+
+/**
+ * @author 三刀
+ * @version V1.0 , 2018/6/9
+ */
+public class BufferRange {
+    public int start = -1;
+    public int length;
+    public boolean isOk = false;
+
+    public void reset() {
+        start = -1;
+        length = 0;
+        isOk = false;
+    }
+}

+ 32 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/BufferRanges.java

@@ -0,0 +1,32 @@
+package org.smartboot.http;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author 三刀
+ * @version V1.0 , 2018/6/10
+ */
+public class BufferRanges {
+
+    public List<BufferRange> headers = new ArrayList<>();
+
+    public BufferRange getReadableRange() {
+        BufferRange bufferRange;
+        if (headers.size() == 0) {
+            bufferRange = new BufferRange();
+            headers.add(bufferRange);
+            return bufferRange;
+        }
+        bufferRange = headers.get(headers.size() - 1);
+        if (bufferRange.isOk) {
+            bufferRange = new BufferRange();
+            headers.add(bufferRange);
+        }
+        return bufferRange;
+    }
+
+    public void reset() {
+        headers.clear();
+    }
+}

+ 43 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/Consts.java

@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2018, org.smartboot. All rights reserved.
+ * project name: smart-socket
+ * file name: Consts.java
+ * Date: 2018-02-06
+ * Author: sandao
+ */
+
+package org.smartboot.http;
+
+import java.nio.charset.Charset;
+
+public interface Consts {
+
+    /**
+     * Horizontal space
+     */
+    public static final byte SP = 32;
+
+
+    /**
+     * Carriage return
+     */
+    public static final byte CR = 13;
+
+
+    /**
+     * Line feed character
+     */
+    public static final byte LF = 10;
+
+    /**
+     * Colon ':'
+     */
+    public static final byte COLON = 58;
+
+
+    public static final byte[] CRLF = {Consts.CR, Consts.LF};
+
+    byte[] COLON_ARRAY = {COLON};
+
+    byte[] SP_ARRAY = {SP};
+}

+ 29 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/HttpBootstrap.java

@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2018, org.smartboot. All rights reserved.
+ * project name: smart-socket
+ * file name: HttpBootstrap.java
+ * Date: 2018-01-28
+ * Author: sandao
+ */
+
+package org.smartboot.http;
+
+import org.smartboot.socket.transport.AioQuickServer;
+
+import java.io.IOException;
+
+public class HttpBootstrap {
+
+    public static void main(String[] args) {
+        AioQuickServer<HttpEntityV2> server = new AioQuickServer<HttpEntityV2>(8080, new HttpServerV2Protocol(), new HttpV2MessageProcessor());
+        server.setWriteQueueSize(0)
+                .setReadBufferSize(1280)
+        ;
+
+        try {
+            server.start();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 55 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/HttpEntityV2.java

@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2018, org.smartboot. All rights reserved.
+ * project name: smart-socket
+ * file name: HttpV2Entity.java
+ * Date: 2018-01-23
+ * Author: sandao
+ */
+
+package org.smartboot.http;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Http消息体,兼容请求与响应
+ *
+ * @author 三刀 2018/06/02
+ */
+public class HttpEntityV2 {
+    public final BufferRange verb = new BufferRange();
+    public final BufferRange uri = new BufferRange();
+    public final BufferRange protocol = new BufferRange();
+    public final BufferRanges header = new BufferRanges();
+    public int initPosition = 0;
+    public State state = State.verb;
+    public ByteBuffer buffer;
+    private int currentPosition = 0;
+
+    public void rest() {
+        verb.reset();
+        uri.reset();
+        protocol.reset();
+        header.reset();
+        buffer = null;
+        initPosition = 0;
+        setCurrentPosition(0);
+        state = State.verb;
+    }
+
+    public int getCurrentPosition() {
+        return currentPosition;
+    }
+
+    public void setCurrentPosition(int currentPosition) {
+        this.currentPosition = currentPosition;
+    }
+
+    public byte[] getBytes(BufferRange range) {
+        int p = buffer.position();
+        byte[] b = new byte[range.length];
+        buffer.position(range.start);
+        buffer.get(b);
+        buffer.position(p);
+        return b;
+    }
+}

+ 154 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/HttpServerV2Protocol.java

@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2018, org.smartboot. All rights reserved.
+ * project name: smart-socket
+ * file name: HttpV2Protocol.java
+ * Date: 2018-01-23
+ * Author: sandao
+ */
+
+package org.smartboot.http;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.smartboot.socket.Protocol;
+import org.smartboot.socket.transport.AioSession;
+
+import java.nio.ByteBuffer;
+
+/**
+ * Http消息解析器,仅解析Header部分即可
+ * Created by 三刀 on 2017/6/20.
+ */
+final class HttpServerV2Protocol implements Protocol<HttpEntityV2> {
+
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(HttpServerV2Protocol.class);
+
+    @Override
+    public HttpEntityV2 decode(ByteBuffer buffer, AioSession<HttpEntityV2> session, boolean eof) {
+        if (!buffer.hasRemaining() || eof) {
+            return null;
+        }
+        buffer.mark();
+
+        HttpEntityV2 entityV2 = session.getAttachment();
+        buffer.position(entityV2.getCurrentPosition());
+
+
+        State curState = entityV2.state;
+        boolean flag = false;
+        do {
+            flag = false;
+            switch (curState) {
+                case verb:
+                    entityV2.initPosition = buffer.position();
+                    scanUntil(buffer, Consts.SP, entityV2.verb);
+                    if (entityV2.verb.isOk) {
+                        curState = State.uri;
+                    } else {
+                        break;
+                    }
+                case uri:
+                    scanUntil(buffer, Consts.SP, entityV2.uri);
+                    if (entityV2.uri.isOk) {
+                        curState = State.protocol;
+                    } else {
+                        break;
+                    }
+                case protocol:
+                    scanUntil(buffer, Consts.CR, entityV2.protocol);
+                    if (entityV2.protocol.isOk) {
+                        curState = State.request_line_end;
+                    } else {
+                        break;
+                    }
+                case request_line_end:
+                    if (buffer.remaining() >= 2) {
+                        if (buffer.get() != Consts.LF) {
+                            LOGGER.error(buffer.toString());
+                            throw new RuntimeException("");
+                        }
+                        if (buffer.get(buffer.position()) == Consts.CR) {
+                            curState = State.head_line_end;
+                        } else {
+                            curState = State.head_line;
+                        }
+                    } else {
+                        break;
+                    }
+                case head_line:
+                    BufferRange headRange = entityV2.header.getReadableRange();
+                    scanUntil(buffer, Consts.CR, headRange);
+                    if (headRange.isOk) {
+                        curState = State.head_line_LF;
+                    } else {
+                        break;
+                    }
+                case head_line_LF:
+                    if (buffer.remaining() >= 2) {
+                        if (buffer.get() != Consts.LF) {
+                            throw new RuntimeException("");
+                        }
+                        if (buffer.get(buffer.position()) == Consts.CR) {
+                            curState = State.head_line_end;
+                        } else {
+                            curState = State.head_line;
+                            flag = true;
+                            break;
+                        }
+                    } else {
+                        break;
+                    }
+                case head_line_end:
+                    if (buffer.remaining() < 2) {
+                        break;
+                    }
+                    if (buffer.get() == Consts.CR && buffer.get() == Consts.LF) {
+                        curState = State.finished;
+                        break;
+                    } else {
+                        throw new RuntimeException();
+                    }
+                default:
+                    throw new RuntimeException("aa");
+            }
+        } while (flag);
+        if (curState == State.finished) {
+            entityV2.setCurrentPosition(buffer.position());
+            entityV2.buffer = buffer;
+            return entityV2;
+        }
+        entityV2.setCurrentPosition(buffer.position());
+        entityV2.state = curState;
+        buffer.reset();
+        if (buffer.limit() == buffer.capacity()) {
+            throw new RuntimeException("buffer full");
+        }
+        return null;
+    }
+
+    @Override
+    public ByteBuffer encode(HttpEntityV2 httpRequest, AioSession<HttpEntityV2> session) {
+        return null;
+    }
+
+    private void scanUntil(ByteBuffer buffer, byte split, BufferRange bufferRange) {
+        int index = buffer.position();
+        bufferRange.start = index;
+        int remaing = buffer.remaining();
+        byte[] data = buffer.array();
+        while (remaing-- > 0) {
+            if (data[index] == split) {
+                bufferRange.length = index - bufferRange.start;
+                bufferRange.isOk = true;
+                buffer.position(++index);
+                return;
+            } else {
+                index++;
+            }
+        }
+        bufferRange.start = -1;
+    }
+
+
+}

+ 73 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/HttpV2MessageProcessor.java

@@ -0,0 +1,73 @@
+package org.smartboot.http;
+
+import org.smartboot.socket.MessageProcessor;
+import org.smartboot.socket.StateMachineEnum;
+import org.smartboot.socket.transport.AioSession;
+
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+/**
+ * @author 三刀
+ * @version V1.0 , 2018/6/10
+ */
+public class HttpV2MessageProcessor implements MessageProcessor<HttpEntityV2> {
+    private static String b = "HTTP/1.1 200 OK\r\n" +
+            "Server:smart-socket\r\n" +
+            "Connection:keep-alive\r\n" +
+            "Host:localhost\r\n" +
+            "Content-Length:31\r\n" +
+            "Date:Wed, 11 Apr 2018 12:35:01 GMT\r\n\r\n" +
+            "Hello smart-socket http server!";
+
+    private byte[] plainText;
+    private byte[] json;
+
+    public HttpV2MessageProcessor() {
+        plainText = ("HTTP/1.1 200 OK\r\n" +
+                "Content-Length: 13\r\n" +
+                "Content-Type: text/plain; charset=UTF-8\r\n" +
+                "Server: smart-socket\r\n" +
+                "Date: Wed, 17 Apr 2013 12:00:00 GMT\r\n" +
+                "\r\n" +
+                "Hello, World!").getBytes();
+
+        json = ("HTTP/1.1 200 OK\r\n" +
+                "Content-Type: application/json\r\n" +
+                "Content-Length: 27\r\n" +
+                "Server: Example\r\n" +
+                "Date: Wed, 17 Apr 2013 12:00:00 GMT\r\n" +
+                "\r\n" +
+                "{\"message\":\"Hello, World!\"}").getBytes();
+    }
+
+    @Override
+    public void process(AioSession<HttpEntityV2> session, HttpEntityV2 msg) {
+        try {
+            String uri = new String(msg.getBytes(msg.uri));
+            if ("/json".equals(uri)) {
+                session.write(ByteBuffer.wrap(json));
+            } else if ("/plaintext".equals(uri)) {
+                session.write(ByteBuffer.wrap(plainText));
+            } else {
+                session.write(ByteBuffer.wrap(b.getBytes()));
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            msg.rest();
+        }
+    }
+
+    @Override
+    public void stateEvent(AioSession<HttpEntityV2> session, StateMachineEnum stateMachineEnum, Throwable throwable) {
+        switch (stateMachineEnum) {
+            case NEW_SESSION:
+                session.setAttachment(new HttpEntityV2());
+                break;
+            case PROCESS_EXCEPTION:
+                session.close();
+                break;
+        }
+    }
+}

+ 12 - 0
frameworks/Java/smart-socket/src/main/java/org/smartboot/http/State.java

@@ -0,0 +1,12 @@
+package org.smartboot.http;
+
+public enum State {
+    verb,
+    uri,
+    protocol,
+    request_line_end,
+    head_line,
+    head_line_LF,
+    head_line_end,
+    finished;
+}