diff --git a/frameworks/Java/aio-socket/.dockerignore b/frameworks/Java/aio-socket/.dockerignore new file mode 100644 index 00000000000..cba5dfe3c3b --- /dev/null +++ b/frameworks/Java/aio-socket/.dockerignore @@ -0,0 +1,19 @@ +.github +.git +.DS_Store +docs +kubernetes +node_modules +/.svelte-kit +/package +.env +.env.* +vite.config.js.timestamp-* +vite.config.ts.timestamp-* +__pycache__ +.env +_old +uploads +.ipynb_checkpoints +**/*.db +_test \ No newline at end of file diff --git a/frameworks/Java/aio-socket/.gitignore b/frameworks/Java/aio-socket/.gitignore new file mode 100644 index 00000000000..2f089945614 --- /dev/null +++ b/frameworks/Java/aio-socket/.gitignore @@ -0,0 +1,3 @@ +/target/ +logs +.settings \ No newline at end of file diff --git a/frameworks/Java/aio-socket/README.md b/frameworks/Java/aio-socket/README.md new file mode 100644 index 00000000000..118b271982c --- /dev/null +++ b/frameworks/Java/aio-socket/README.md @@ -0,0 +1,77 @@ +# t-io Benchmarking Test + +This is the tio-server portion of a [benchmarking test suite](../) comparing a variety of web development platforms. + +## Controller + +These implementations use the tio-server's controller. + +### Plaintext Test + +* [Plaintext test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + +### JSON Serialization Test + +* [JSON test source](src/main/java/com/litongjava/tio/http/server/controller/IndexController.java) + + +## Versions +3.7.3.v20231218-RELEASE (https://gitee.com/litongjava/t-io) + +## Test URLs + +All implementations use the same URLs. + +### Plaintext Test + + http://localhost:8080/plaintext + +### JSON Encoding Test + + http://localhost:8080/json + + + + ## Hot to run + ### install mysql 8 + - 1.please instal mysql 8.0.32,example cmd + ``` + docker run --restart=always -d --name mysql_8 --hostname mysql \ +-p 3306:3306 \ +-e 'MYSQL_ROOT_PASSWORD=robot_123456#' -e 'MYSQL_ROOT_HOST=%' -e 'MYSQL_DATABASE=hello_world' \ +mysql/mysql-server:8.0.32 \ +--character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci --lower_case_table_names=1 + ``` + - 2.create database schema hello_world + - 3.create tablle,[example](sql/hello_world.sql) + - 4.import data + + ### docker + ``` + docker build -t tio-server-benchmark -f tio-server.dockerfile . +``` +The run is to specify the mysql database +``` +docker run --rm -p 8080:8080 \ +-e JDBC_URL="jdbc:mysql://192.168.3.9/hello_world" \ +-e JDBC_USER="root" \ +-e JDBC_PSWD="robot_123456#" \ +tio-server-benchmark +``` + +### windows + +-windows +``` +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar --JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false --JDBC_USER=root --JDBC_PSWD=robot_123456# +``` +or +``` +set JDBC_URL=jdbc:mysql://192.168.3.9/hello_world +set jdbc.user=root +set JDBC_PSWD=robot_123456# +D:\java\jdk1.8.0_121\bin\java -jar target\tio-server-benchmark-1.0.jar +``` + + + diff --git a/frameworks/Java/aio-socket/aio-socket.dockerfile b/frameworks/Java/aio-socket/aio-socket.dockerfile new file mode 100644 index 00000000000..7aa11987383 --- /dev/null +++ b/frameworks/Java/aio-socket/aio-socket.dockerfile @@ -0,0 +1,19 @@ +FROM litongjava/maven:3.8.8-jdk8u391 AS builder +WORKDIR /app + +COPY pom.xml pom.xml +RUN mvn dependency:go-offline -q + +COPY src src +RUN mvn package -Passembly -q +RUN ls -l && ls -l target + +FROM litongjava/jre:8u391-stable-slim + +WORKDIR /app + +COPY --from=builder /app/target/aio-socket-benchmark-1.0-jar-with-dependencies.jar /app/aio-socket-benchmark-1.0.jar + +EXPOSE 8080 + +CMD ["java", "-server", "-XX:+UseNUMA", "-XX:+UseParallelGC","-cp", "/app/aio-socket-benchmark-1.0.jar","com.litongjava.aio.http.server.HttpServer"] \ No newline at end of file diff --git a/frameworks/Java/aio-socket/benchmark_config.json b/frameworks/Java/aio-socket/benchmark_config.json new file mode 100644 index 00000000000..135582cd342 --- /dev/null +++ b/frameworks/Java/aio-socket/benchmark_config.json @@ -0,0 +1,23 @@ +{ + "framework": "aio-socket", + "tests": [{ + "default": { + "plaintext_url": "/plaintext", + "json_url": "/json", + "port": 8080, + "approach": "Realistic", + "classification": "Micro", + "framework": "aio-socket", + "language": "Java", + "flavor": "None", + "orm": "Raw", + "platform": "t-io", + "webserver": "None", + "os": "Linux", + "database_os": "Linux", + "display_name": "aio-socket", + "notes": "aio-socket", + "versus": "t-io" + } + }] +} diff --git a/frameworks/Java/aio-socket/config.toml b/frameworks/Java/aio-socket/config.toml new file mode 100644 index 00000000000..31b198ee34b --- /dev/null +++ b/frameworks/Java/aio-socket/config.toml @@ -0,0 +1,15 @@ +[framework] +name = "t-io" + +[main] +urls.plaintext = "/plaintext" +urls.json = "/json" +approach = "Realistic" +classification = "Micro" +database = "None" +database_os = "Linux" +os = "Linux" +orm = "Raw" +platform = "t-io" +webserver = "None" +versus = "t-io" diff --git a/frameworks/Java/aio-socket/pom.xml b/frameworks/Java/aio-socket/pom.xml new file mode 100644 index 00000000000..2b5dacefe65 --- /dev/null +++ b/frameworks/Java/aio-socket/pom.xml @@ -0,0 +1,90 @@ + + 4.0.0 + com.litongjava + aio-socket-benchmark + 1.0 + ${project.artifactId} + + UTF-8 + 1.8 + ${java.version} + ${java.version} + com.litongjava.aio.http.server.HttpServer + + + + com.litongjava + aio-socket + 1.0.1 + + + com.alibaba + fastjson + 2.0.39 + + + + + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + + + + central + Central Repository + https://repo.maven.apache.org/maven2 + + + sonatype-nexus-snapshots + Sonatype Nexus Snapshots + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + + true + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + false + + + + + maven-assembly-plugin + 3.1.0 + + + jar-with-dependencies + + + + + make-assembly + package + + single + + + + + + + \ No newline at end of file diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java new file mode 100644 index 00000000000..fa954b4cef4 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/HttpServer.java @@ -0,0 +1,169 @@ +package com.litongjava.aio.http.server; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.nio.ByteBuffer; +import java.nio.channels.AsynchronousChannelGroup; +import java.nio.channels.AsynchronousSocketChannel; +import java.nio.channels.CompletionHandler; +import java.nio.charset.StandardCharsets; +import java.time.ZonedDateTime; +import java.time.format.DateTimeFormatter; +import java.time.ZoneId; +import java.util.concurrent.ThreadFactory; + +import com.alibaba.fastjson.JSON; +import com.litongjava.aio.http.server.model.Message; +import com.litongjava.enhance.buffer.BufferPage; +import com.litongjava.enhance.buffer.BufferPagePool; +import com.litongjava.enhance.buffer.VirtualBuffer; +import com.litongjava.enhance.channel.EnhanceAsynchronousChannelProvider; +import com.litongjava.enhance.channel.EnhanceAsynchronousServerSocketChannel; + +public class HttpServer { + + private static int cpuNum = Runtime.getRuntime().availableProcessors(); + private static BufferPagePool pool = new BufferPagePool(0, 1024 * cpuNum, true); + private static BufferPage bufferPage = pool.allocateBufferPage(); + private static final String HELLO_WORLD = "Hello, World!"; + + public static void main(String[] args) throws Exception { + + // 创建异步通道提供者 + EnhanceAsynchronousChannelProvider provider = new EnhanceAsynchronousChannelProvider(false); + + // 创建通道组 + AsynchronousChannelGroup group = provider.openAsynchronousChannelGroup(2, new ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + return new Thread(r, "http-server-thread"); + } + }); + + // 创建服务器通道并绑定端口 + EnhanceAsynchronousServerSocketChannel server = (EnhanceAsynchronousServerSocketChannel) provider.openAsynchronousServerSocketChannel(group); + server.bind(new InetSocketAddress(8080), 0); + + System.out.println("HTTP Server 正在监听端口 8080 ..."); + + // 异步接受连接 + server.accept(null, new CompletionHandler() { + @Override + public void completed(AsynchronousSocketChannel channel, Object attachment) { + // 继续接收其他连接 + server.accept(null, this); + handleClient(channel); + } + + @Override + public void failed(Throwable exc, Object attachment) { + exc.printStackTrace(); + } + }); + + // 主线程阻塞 + Thread.currentThread().join(); + } + + private static void handleClient(AsynchronousSocketChannel channel) { + VirtualBuffer virtualBuffer = bufferPage.allocate(8192); + ByteBuffer buffer = virtualBuffer.buffer(); + + channel.read(buffer, virtualBuffer, new CompletionHandler() { + @Override + public void completed(Integer result, VirtualBuffer attachment) { + try { + if (result > 0) { + buffer.flip(); + byte[] bytes = new byte[buffer.remaining()]; + buffer.get(bytes); + String request = new String(bytes, StandardCharsets.UTF_8); + + // 生成当前时间,格式为 RFC 1123 格式 + String date = DateTimeFormatter.RFC_1123_DATE_TIME.format(ZonedDateTime.now(ZoneId.of("GMT"))); + + ByteBuffer responseBuffer; + if (request.startsWith("GET /plaintext")) { + String body = "Hello, World!"; + String httpResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n" + + "Server: aio-socket\r\n" + + "Content-Type: text/plain\r\n" + + "Date: " + date + "\r\n" + + "\r\n" + + body; + responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); + + } else if (request.startsWith("GET /json")) { + String jsonString = JSON.toJSONString(new Message(HELLO_WORLD)); + int length = jsonString.getBytes(StandardCharsets.UTF_8).length; + String httpResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + length + "\r\n" + + "Server: aio-socket\r\n" + + "Content-Type: application/json\r\n" + + "Date: " + date + "\r\n" + + "\r\n" + + jsonString; + responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); + } else { + String body = "Hello, World!"; + String httpResponse = "HTTP/1.1 200 OK\r\n" + + "Content-Length: " + body.getBytes(StandardCharsets.UTF_8).length + "\r\n" + + "Content-Type: text/plain\r\n" + + "Date: " + date + "\r\n" + + "\r\n" + + body; + responseBuffer = ByteBuffer.wrap(httpResponse.getBytes(StandardCharsets.UTF_8)); + } + + // 异步写响应 + channel.write(responseBuffer, attachment, new CompletionHandler() { + @Override + public void completed(Integer result, VirtualBuffer attachment) { + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + attachment.clean(); + } + } + + @Override + public void failed(Throwable exc, VirtualBuffer attachment) { + exc.printStackTrace(); + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + attachment.clean(); + } + } + }); + } else { + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } finally { + // 注意:如果在写操作中已经归还了虚拟缓冲区,则不要重复释放 + } + } + + @Override + public void failed(Throwable exc, VirtualBuffer attachment) { + exc.printStackTrace(); + try { + channel.close(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + attachment.clean(); + } + } + }); + } +} diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Fortune.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Fortune.java new file mode 100644 index 00000000000..76f56b22dc9 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Fortune.java @@ -0,0 +1,23 @@ +package com.litongjava.aio.http.server.model; + +public final class Fortune { + + public Long id; + public String message; + + public Fortune() { + } + + public Fortune(Long id, String message) { + this.id = id; + this.message = message; + } + + public Long getId() { + return id; + } + + public String getMessage() { + return message; + } +} \ No newline at end of file diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Message.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Message.java new file mode 100644 index 00000000000..2365bf4d708 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/Message.java @@ -0,0 +1,13 @@ +package com.litongjava.aio.http.server.model; + +public final class Message { + private final String message; + + public Message(String message) { + this.message = message; + } + + public String getMessage() { + return message; + } +} diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/World.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/World.java new file mode 100644 index 00000000000..3fec0068ea5 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/model/World.java @@ -0,0 +1,32 @@ +package com.litongjava.aio.http.server.model; + +public final class World { + + public int id; + public int randomnumber; + + protected World() { + } + + public World(int id, int randomnumber) { + this.id = id; + this.randomnumber = randomnumber; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getRandomnumber() { + return randomnumber; + } + + public void setRandomnumber(int randomnumber) { + this.randomnumber = randomnumber; + } + +} \ No newline at end of file diff --git a/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/utils/RandomUtils.java b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/utils/RandomUtils.java new file mode 100644 index 00000000000..c2b73f8dca2 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/java/com/litongjava/aio/http/server/utils/RandomUtils.java @@ -0,0 +1,36 @@ +package com.litongjava.aio.http.server.utils; + +import java.util.concurrent.ThreadLocalRandom; +import java.util.stream.IntStream; + +public class RandomUtils { + + private static final int MIN_WORLD_NUMBER = 1; + private static final int MAX_WORLD_NUMBER_PLUS_ONE = 10_001; + // private static final int MAX_WORLD_NUMBER_PLUS_ONE = 30; + + public static int randomWorldNumber() { + return ThreadLocalRandom.current().nextInt(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE); + } + + public static IntStream randomWorldNumbers() { + return ThreadLocalRandom.current().ints(MIN_WORLD_NUMBER, MAX_WORLD_NUMBER_PLUS_ONE) + // distinct() allows us to avoid using Hibernate's first-level cache in + // the JPA-based implementation. Using a cache like that would bypass + // querying the database, which would violate the test requirements. + .distinct(); + } + + public static int parseQueryCount(String textValue) { + if (textValue == null) { + return 1; + } + int parsedValue; + try { + parsedValue = Integer.parseInt(textValue); + } catch (NumberFormatException e) { + return 1; + } + return Math.min(500, Math.max(1, parsedValue)); + } +} diff --git a/frameworks/Java/aio-socket/src/main/resources/app.properties b/frameworks/Java/aio-socket/src/main/resources/app.properties new file mode 100644 index 00000000000..52083ea13ff --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/app.properties @@ -0,0 +1,9 @@ +http.response.header.showServer=true +server.port=8080 +#JDBC_URL=jdbc:mysql://192.168.3.9/hello_world?useSSL=false&allowPublicKeyRetrieval=true +#JDBC_USER=root +#JDBC_PSWD=robot_123456# + +JDBC_URL=jdbc:mysql://tfb-database/hello_world +JDBC_USER=benchmarkdbuser +JDBC_PSWD=benchmarkdbpass \ No newline at end of file diff --git a/frameworks/Java/aio-socket/src/main/resources/ehcache.xml b/frameworks/Java/aio-socket/src/main/resources/ehcache.xml new file mode 100644 index 00000000000..79b79e49479 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/ehcache.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/frameworks/Java/aio-socket/src/main/resources/logback.xml b/frameworks/Java/aio-socket/src/main/resources/logback.xml new file mode 100644 index 00000000000..6065c075e78 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/logback.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + + + + ${CONSOLE_LOG_PATTERN} + + + + ${LOG_HOME}/log.%d{yyyyMMddHH}.%i.log + + 180 + + 100MB + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frameworks/Java/aio-socket/src/main/resources/templates/fortunes.html b/frameworks/Java/aio-socket/src/main/resources/templates/fortunes.html new file mode 100644 index 00000000000..1f6817df007 --- /dev/null +++ b/frameworks/Java/aio-socket/src/main/resources/templates/fortunes.html @@ -0,0 +1,20 @@ + + + + Fortunes + + + + + + + + #for(fortune : fortunes) + + + + + #end +
idmessage
#(fortune.id)#escape(fortune.message)
+ +