diff --git a/build.gradle.kts b/build.gradle.kts index f5de2c4..b73e939 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -38,6 +38,8 @@ dependencies { testRuntimeOnly("org.junit.platform:junit-platform-launcher") implementation("org.jetbrains:annotations:24.0.0") annotationProcessor("org.jetbrains:annotations:24.0.0") + implementation("com.mingliqiye:network-endpoint:1.0.2") + implementation("com.mingliqiye:string-utilts:1.0.4") } tasks.test { diff --git a/src/main/java/com/mingliqiye/utils/BufferBytesEntity.java b/src/main/java/com/mingliqiye/utils/BufferBytesEntity.java new file mode 100644 index 0000000..fc0b07b --- /dev/null +++ b/src/main/java/com/mingliqiye/utils/BufferBytesEntity.java @@ -0,0 +1,35 @@ +package com.mingliqiye.utils; + +public class BufferBytesEntity { + + /** + * 数据 + */ + private final byte[] bytes; + /** + * 数据大小 + */ + private final int len; + /** + * 缓存区大小 + */ + private final int buffer; + + public BufferBytesEntity(byte[] bytes, int len, int buffer) { + this.bytes = bytes; + this.len = len; + this.buffer = buffer; + } + + public byte[] getBytes() { + return bytes; + } + + public int getLen() { + return len; + } + + public int getBuffer() { + return buffer; + } +} diff --git a/src/main/java/com/mingliqiye/utils/DefTcpServerImplementation.java b/src/main/java/com/mingliqiye/utils/DefTcpServerImplementation.java new file mode 100644 index 0000000..047d03c --- /dev/null +++ b/src/main/java/com/mingliqiye/utils/DefTcpServerImplementation.java @@ -0,0 +1,63 @@ +package com.mingliqiye.utils; + +import com.mingliqiye.network.endpoint.NetworkEndpoint; +import java.net.InetSocketAddress; +import java.net.ServerSocket; + +public class DefTcpServerImplementation extends TcpServerImplementation { + + boolean connect(TcpSocketClient client, String id) { + System.out.println( + StringUtil.format( + "客户端 {} ID={} 连接成功", + client.getEndpoint().toHostPortString(), + id + ) + ); + return true; + } + + void disconnect(TcpSocketClient client, String id) { + System.out.println( + StringUtil.format( + "客户端 {} ID={} 断开连接", + client.getEndpoint().toHostPortString(), + id + ) + ); + } + + void reception( + TcpSocketClient client, + BufferBytesEntity bufferBytesEntity + ) { + System.out.println( + StringUtil.format( + "来自客户端 {} ID:{} 的数据 大小:{}", + client.getEndpoint().toHostPortString(), + client.getIds(), + bufferBytesEntity.getLen() + ) + ); + client.send( + bufferBytesEntity.getBytes(), + 0, + bufferBytesEntity.getLen() + ); + } + + void started(ServerSocket serverSocket) { + System.out.println( + StringUtil.format( + "服务器启动 监听 {}", + NetworkEndpoint.of( + (InetSocketAddress) serverSocket.getLocalSocketAddress() + ).toHostPortString() + ) + ); + } + + void closed() { + System.out.println("服务器已经关闭"); + } +} diff --git a/src/main/java/com/mingliqiye/utils/Main.java b/src/main/java/com/mingliqiye/utils/Main.java new file mode 100644 index 0000000..2bae5a4 --- /dev/null +++ b/src/main/java/com/mingliqiye/utils/Main.java @@ -0,0 +1,12 @@ +package com.mingliqiye.utils; + +import com.mingliqiye.network.endpoint.NetworkEndpoint; + +public class Main { + + public static void main(String[] args) { + TcpSocketServer tcpSocketServer = new TcpSocketServer(null); + tcpSocketServer.bing(NetworkEndpoint.of("127.0.0.1:3621")); + tcpSocketServer.start(); + } +} diff --git a/src/main/java/com/mingliqiye/utils/TcpServerImplementation.java b/src/main/java/com/mingliqiye/utils/TcpServerImplementation.java new file mode 100644 index 0000000..6929881 --- /dev/null +++ b/src/main/java/com/mingliqiye/utils/TcpServerImplementation.java @@ -0,0 +1,34 @@ +package com.mingliqiye.utils; + +import java.net.ServerSocket; + +/** + * 回调函数们 + * @see DefTcpServerImplementation 示例 + */ +public abstract class TcpServerImplementation { + + /** + * 连接回调函数 + * @param client 客户端 + * @param id 客户端ID + * @return 是否允许连接 + */ + abstract boolean connect(TcpSocketClient client, String id); + + /** + * 断开连接回调函数 + * @param client 客户端 + * @param id 客户端ID + */ + abstract void disconnect(TcpSocketClient client, String id); + + abstract void reception( + TcpSocketClient client, + BufferBytesEntity bufferBytesEntity + ); + + abstract void started(ServerSocket serverSocket); + + abstract void closed(); +} diff --git a/src/main/java/com/mingliqiye/utils/TcpSocketClient.java b/src/main/java/com/mingliqiye/utils/TcpSocketClient.java new file mode 100644 index 0000000..be4fe44 --- /dev/null +++ b/src/main/java/com/mingliqiye/utils/TcpSocketClient.java @@ -0,0 +1,127 @@ +package com.mingliqiye.utils; + +import com.mingliqiye.network.endpoint.NetworkEndpoint; +import com.mingliqiye.network.endpoint.NetworkException; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.net.InetSocketAddress; +import java.net.Socket; + +public class TcpSocketClient extends Thread { + + private final InputStream inputStream; + private final OutputStream outputStream; + private final Socket socket; + private final TcpServerImplementation tcpServerImplementation; + private final TcpSocketServer father; + private final String id; + private final NetworkEndpoint endpoint; + private boolean closed = false; + + public String getIds() { + return id; + } + + public TcpSocketClient( + InputStream inputStream, + OutputStream outputStream, + Socket socket, + TcpServerImplementation tcpServerImplementation, + TcpSocketServer father, + String id + ) { + this.inputStream = inputStream; + this.outputStream = outputStream; + this.socket = socket; + this.tcpServerImplementation = tcpServerImplementation; + this.father = father; + this.id = id; + this.endpoint = NetworkEndpoint.of( + (InetSocketAddress) socket.getRemoteSocketAddress() + ); + } + + public void run() { + while (!Thread.currentThread().isInterrupted()) { + try { + BufferBytesEntity bufferBytesEntity = recv(1024); + if (bufferBytesEntity.getLen() == -1) break; + tcpServerImplementation.reception(this, bufferBytesEntity); + } catch (NetworkException e) { + break; + } + } + father.closeItem(id); + } + + /** + * 发送指定字节长度 + * @param bytes 字节 + * @param off 位移 + * @param len 长度 + */ + public void send(byte[] bytes, int off, int len) { + try { + outputStream.write(bytes, off, len); + } catch (IOException e) { + throw new NetworkException(e); + } + } + + /** + * 发送字节
+ * 注意 byte数组有多大发多大数组内空着的发送 0X00 + * @param bytes 字节 + */ + public void send(byte[] bytes) { + send(bytes, 0, bytes.length); + } + + /** + * 读取指定大小buffer的数据 + * + * @param buffer 缓存区大小 + * @return BufferBytesEntity + * @see BufferBytesEntity + */ + public BufferBytesEntity recv(int buffer) { + byte[] bytes = new byte[buffer]; + try { + return new BufferBytesEntity( + bytes, + inputStream.read(bytes), + buffer + ); + } catch (IOException e) { + throw new NetworkException(e); + } + } + + public void close() { + if (closed) { + return; + } + closed = true; + tcpServerImplementation.disconnect(this, id); + try { + inputStream.close(); + } catch (IOException e) { + throw new NetworkException(e); + } + try { + outputStream.close(); + } catch (IOException e) { + throw new NetworkException(e); + } + try { + socket.close(); + } catch (IOException e) { + throw new NetworkException(e); + } + } + + public NetworkEndpoint getEndpoint() { + return endpoint; + } +} diff --git a/src/main/java/com/mingliqiye/utils/TcpSocketServer.java b/src/main/java/com/mingliqiye/utils/TcpSocketServer.java new file mode 100644 index 0000000..d25308e --- /dev/null +++ b/src/main/java/com/mingliqiye/utils/TcpSocketServer.java @@ -0,0 +1,100 @@ +package com.mingliqiye.utils; + +import com.mingliqiye.network.endpoint.NetworkEndpoint; +import com.mingliqiye.network.endpoint.NetworkException; +import java.io.IOException; +import java.io.InterruptedIOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; + +/** + * tcp 服务器 类 + */ +public class TcpSocketServer extends Thread implements AutoCloseable { + + /** + * 客户端字典(线程安全的) + */ + private final Map clientMap = + new ConcurrentHashMap<>(); + + private ServerSocket serverSocket; + + private final TcpServerImplementation tcpServerImplementation; + + public TcpSocketServer(TcpServerImplementation tcpServerImplementation) { + if (tcpServerImplementation == null) { + tcpServerImplementation = new DefTcpServerImplementation(); + } + this.tcpServerImplementation = tcpServerImplementation; + } + + /** + * 绑定地址和端口号 + * + * @param endpoint 地址和端口号 + * @throws NetworkException 网络错误 + */ + public void bing(NetworkEndpoint endpoint) { + try { + serverSocket = new ServerSocket(); + serverSocket.bind(endpoint.toInetSocketAddress()); + } catch (IOException e) { + throw new NetworkException(e); + } + } + + public void run() { + tcpServerImplementation.started(serverSocket); + while (!Thread.currentThread().isInterrupted()) { + try { + String uuid = UUID.randomUUID().toString(); + Socket socket = serverSocket.accept(); + TcpSocketClient tcpSocketClient = new TcpSocketClient( + socket.getInputStream(), + socket.getOutputStream(), + socket, + tcpServerImplementation, + this, + uuid + ); + if (!tcpServerImplementation.connect(tcpSocketClient, uuid)) { + tcpSocketClient.close(); + return; + } + clientMap.put(uuid, tcpSocketClient); + tcpSocketClient.start(); + } catch (InterruptedIOException e) { + Thread.currentThread().interrupt(); + break; + } catch (IOException e) { + throw new NetworkException(e); + } + } + } + + public void closeItem(String id) { + TcpSocketClient tcpSocketClient = clientMap.get(id); + if (tcpSocketClient == null) { + return; + } + clientMap.remove(id); + tcpSocketClient.close(); + } + + @Override + public void close() { + tcpServerImplementation.closed(); + clientMap.forEach((k, v) -> { + v.close(); + }); + clientMap.clear(); + this.interrupt(); + try { + serverSocket.close(); + } catch (IOException e) {} + } +} diff --git a/workflows/build.yaml b/workflows/build.yaml deleted file mode 100644 index 585f85b..0000000 --- a/workflows/build.yaml +++ /dev/null @@ -1,27 +0,0 @@ -name: Gitea Actions Build -run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀 -on: - push: - branches: - - master -jobs: - Build: - runs-on: ubuntu-dev - steps: - - name: Check out repository code - uses: https://git.mingliqiye.com/Actions/checkout@v4 - - - name: build-test - run: | - source gradle.properties - gradle - gradle build-jar - - - name: Releases - run: | - source gradle.properties - SHA=${{gitea.sha}} - curl -o- https://git.mingliqiye.com/Actions/com.mingliqiye.gitea.releases/raw/branch/master/install.sh | bash - FILENAME="${GROUPSID}-${VERSIONS}.jar" - java -jar com.mingliqiye.gitea.releases.jar -s "${{gitea.server_url}}" -o "${{gitea.repository_owner}}" -r ${{gitea.event.repository.name}} -t "${{gitea.token}}" -ti "Auto releases ${{gitea.sha}} ${VERSIONS}" -b "# Auto releases wtih ${{gitea.event.head_commit.message}} - [${{gitea.sha}}](${{gitea.event.head_commit.url}})" -tn "Auto-Releases-${VERSIONS}-${SHA:0:10}" -a "build/libs" -