{"id":15103689,"url":"https://github.com/zunzhuowei/network-server","last_synced_at":"2026-02-18T13:34:19.710Z","repository":{"id":243081057,"uuid":"811408314","full_name":"zunzhuowei/network-server","owner":"zunzhuowei","description":"Simplifying the construction of network cluster services","archived":false,"fork":false,"pushed_at":"2024-07-30T04:04:52.000Z","size":1250,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-10-26T00:28:47.455Z","etag":null,"topics":["cluster","game","netty","network","server"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/zunzhuowei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-06T14:39:38.000Z","updated_at":"2024-09-25T15:39:16.000Z","dependencies_parsed_at":"2024-06-20T16:56:19.204Z","dependency_job_id":"662cd342-0b62-47db-a532-56a3a475cfbe","html_url":"https://github.com/zunzhuowei/network-server","commit_stats":{"total_commits":108,"total_committers":1,"mean_commits":108.0,"dds":0.0,"last_synced_commit":"f54662467644c9fecb86a889e29345bf4e56b945"},"previous_names":["zunzhuowei/network-server"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/zunzhuowei/network-server","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zunzhuowei%2Fnetwork-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zunzhuowei%2Fnetwork-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zunzhuowei%2Fnetwork-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zunzhuowei%2Fnetwork-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/zunzhuowei","download_url":"https://codeload.github.com/zunzhuowei/network-server/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/zunzhuowei%2Fnetwork-server/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29580808,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-18T08:38:15.585Z","status":"ssl_error","status_checked_at":"2026-02-18T08:38:14.917Z","response_time":162,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cluster","game","netty","network","server"],"created_at":"2024-09-25T19:41:30.477Z","updated_at":"2026-02-18T13:34:14.700Z","avatar_url":"https://github.com/zunzhuowei.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\" style=\"margin: 30px 0 30px; font-weight: bold;\"\u003eNetwork-Server\u003c/h1\u003e\n\u003ch3 align=\"center\"\u003eSimplifying the construction of network cluster services\u003c/h3\u003e\n\n### Introduction\n\n\u003e Based on Netty network framework and Springboot framework.\n\u003e\n\u003e The target is let easy to build a network cluster server. Minimize the use of third-party dependency libraries as much as possible.\n\n### Architecture diagram\n\n![images](docs/pngs/Cluster.png)\n---\n![images](docs/pngs/Nodes.png)\n\n### Existing features\n\n1. Supports multiple network protocols, including TCP, UDP, HTTP, and WEBSOCKET and MQTT; Multiple protocols can be configured on\n   the same port.\n\n[comment]: \u003c\u003e (1. 多网络协议支持，支持TCP、UDP、HTTP、WEBSOCKET协议;同端口支持多种协议（可配置）)\n\n2. Supports multi-node clusters and dynamic node joining and exiting\n\n[comment]: \u003c\u003e (2. 支持多节点集群，支持节点动态加入、退出)\n\n3. Supports message forwarding between internal and external networks\n\n\n4. Supports distributed transactions `server-message-queue` module\n\n### Modules introduction\n\n1. `server-framework`: The `core module` of the framework, which provides the basic configuration of the framework, and\n   the configuration of the network protocol, the message forwarding, and the message processing.\n\n\n2. `server-database`: The `database` module of the framework, use `Mybatis` and `MySQL` to implement the database\n   operation. If you need to use a MySQL database, you can use it.`that is optional`.\n\n\n3. `server-cache`: The `cache` module of the framework, use `Redisson` to implement the `Redis` cache operation, and\n   use `Caffeine` to implement the local cache operation. If you need to use a caching module, you can use\n   it.`that is optional`.\n\n\n4. `server-permission`: The `permission` module of the framework, Use `Spring AOP` and annotations to control interface\n   permissions. The HTTP protocol uses the request header entrainment JWT method,\n   the `permissions` field in the `UserSession` is used for TCP and UDP and WebSocket. If you need\n   to use a `permission` module, you can use it.`that is optional`.\n\n\n5. `server-access-control`: The `access control` module of the framework, Use `Spring AOP` and annotations\n   and `Guava library` to limit the rate of the interface. You can limit the rate of interfaces uniformly or based on\n   user granularity, and configure IP blacklists and whitelists. If you need to use a `access control` module, you can\n   use it.`that is optional`.\n\n\n6. `server-message-queue`: The `message queue` module of the framework, Use the `server-framework` module to develop a\n   message queue module that supports message subscription and message push. If you need to use a `message queue`\n   module, you can use it.`that is optional`.\n\n\n7. `gateway-server`、`hall-server`、`room-server`: These are three `sample nodes` of the cluster, and you can refer to\n   their configurations to get your own cluster\n\n### How to use\n\n1. You must had installed JDK 1.8+ and Maven 3.x\n2. Switch to the project directory and run `mvn clean install`\n3. Add the `server-framework` dependency in your project\n\n```xml\n\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.hbsoo\u003c/groupId\u003e\n    \u003cartifactId\u003eserver-framework\u003c/artifactId\u003e\n    \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n4. Add the `server-framework` Configuration to your Springboot project `application.yml` file.\n\n```yaml\nhbsoo:\n  server:\n    tcpHeader: THBS # TCP header\n    udpHeader: UHBS # UDP header\n    id: 1000 #Current node id\n    threadPoolSize:\n      insideClient: 5 #inside client side business thread pool size\n      insideServer: 5 #inside server side business thread pool size\n      outsideServer: 5 #outside server side business thread pool size\n    outsideServer:\n      enable: true #Whether to enable the outside server\n      port: 5555 #Outside server port\n      protocol: \"TCP,UDP,WEBSOCKET,HTTP,MQTT\" #Outside server protocol,Which protocols to use.\n    insideServers:\n      - host: 192.168.1.104\n        port: 6000\n        type: gateway #Inside server type,that's namespace customized\n        clientSize: 1 #Connect to inside server client size\n        weight: 10 #Inside server weight\n        id: 1000 #Inside server id; At least one id in the list of insideServers is associated with the current node id\n      - host: 192.168.1.104\n        port: 6003\n        type: hall\n        clientSize: 1\n        id: 2000\n      - host: 192.168.1.104\n        port: 6006\n        type: room\n        clientSize: 1\n        id: 3000\n```\n\n5. Define the HTTP message handler as follows\n\n```java\n@OutsideMessageHandler(value = 0, uri = \"/index\", protocol = Protocol.HTTP)\npublic class IndexAction extends HttpServerMessageDispatcher {\n\n    @Override\n    public void handle(ChannelHandlerContext ctx, HttpPacket httpPacket) {\n        List\u003cString\u003e genealogies = new ArrayList\u003c\u003e();\n        genealogies.add(\"zun\");\n        responseJson(httpPacket, genealogies);\n\n        forward2InsideServerUseSender(\n                NetworkPacket.Builder.withDefaultHeader()\n                        .msgType(100).writeStr(genealogies.toString()),\n                \"hall\",\n                \"\",3);\n\n        QueueMessageSender.publish(\"hall\", \"test\", genealogies.toString());\n    }\n}\n```\n\n6. Define the WEBSOCKET message handler as follows\n\n```java\n@OutsideMessageHandler(value = 100, protocol = Protocol.WEBSOCKET)\npublic class LoginChatRoomAction extends ServerMessageDispatcher {\n\n   private static final Logger logger = LoggerFactory.getLogger(LoginChatRoomAction.class);\n\n   @Override\n   public void handle(ChannelHandlerContext ctx, NetworkPacket.Decoder decoder) {\n      String username = decoder.readStr();\n      String channelId = decoder.readStr();\n      int userId = Math.abs(username.hashCode());\n      logger.info(\"login chat room username:{}，channelId:{}，userId:{}\", username, channelId, userId);\n      //notify client login success\n      NetworkPacket.Builder builder = decoder.toBuilder().writeInt(userId).writeStr(Permission.USER.name());\n      builder.sendTcpTo(ctx.channel());\n      //forward to room server\n      forward2insideServerUseSender(builder, \"room\", userId);\n   }\n\n   @Override\n   public Object threadKey(ChannelHandlerContext ctx, NetworkPacket.Decoder decoder) {\n      return decoder.readStr();\n   }\n}\n```\n\n7. Client side network packet and server side network packet as follows\n\n![images](docs/pngs/networkPacket.png)\n\n8. Define the transaction queue message handler at sender side as follows\n```java\n@MessageListener(topic = \"test\", serverType = \"hall\")\npublic class MessageQueueTest implements TransactionQueueMessageSenderHandler {\n    private static final Logger logger = LoggerFactory.getLogger(MessageQueueTest.class);\n\n    @Override\n    public void handleCallback(CallbackMessage callbackMessage) {\n        logger.info(\"callbackMessage = {}\", callbackMessage);\n    }\n\n    @Override\n    public int consumerSize() {\n        return 2;\n    }\n\n    @Override\n    public boolean handle(Long msgId, String objJson) {\n        logger.debug(\"handle msgId = {},objJson = {}\", msgId, objJson);\n        return true;\n    }\n\n    @Override\n    public boolean rollback(Long msgId, String objJson) {\n        logger.debug(\"rollback msgId = {},objJson = {}\", msgId, objJson);\n        return true;\n    }\n}\n```\n9. Define the transaction queue message handler at receiver side as follows\n```java\n@MessageListener(topic = \"test\", serverType = \"hall\")\npublic class MessageQueueTest implements TransactionQueueMessageHandler {\n    private static final Logger logger = LoggerFactory.getLogger(MessageQueueTest.class);\n\n    @Override\n    public boolean handle(Long msgId, String objJson) {\n        logger.debug(\"handle msgId = {},objJson = {}\", msgId, objJson);\n        return false;\n    }\n\n    @Override\n    public boolean rollback(Long msgId, String objJson) {\n        logger.debug(\"rollback msgId = {},objJson = {}\", msgId,objJson);\n        return false;\n    }\n}\n```\n10. Publish the transaction queue message as follows\n```java\n@OutsideMessageHandler(value = 0, uri = \"/index\", protocol = Protocol.HTTP)\npublic class IndexAction extends HttpServerMessageDispatcher {\n\n    @Override\n    public void handle(ChannelHandlerContext ctx, HttpPacket httpPacket) {\n        List\u003cString\u003e genealogies = new ArrayList\u003c\u003e();\n        genealogies.add(\"zun\");\n        responseJson(httpPacket, genealogies);\n        // publish transaction queue message \n        QueueMessageSender.publish(\"hall\", \"test\", genealogies.toString());\n    }\n}\n```\n\n### How to develop\n\n1. You must had installed JDK 1.8+ and Maven 3.x\n2. Clone the project and import it into your IDE\n3. Run the project\n\n### Stress test\n\n* Jvm configuration parameters as follows\n\u003e -Xms512m -Xmx512m -XX:+HeapDumpOnOutOfMemoryError\n\n* The interface tested was IndexAction, as follows\n\n```java\n@PermissionAuth(permission = {})\n//@AccessLimit(userRateSize = 1, globalRateSize = 2)\n@OutsideMessageHandler(value = 0, uri = \"/index\", protocol = Protocol.HTTP)\npublic class IndexAction extends HttpServerMessageDispatcher {\n   @Autowired\n   private IGenealogyService genealogyService;\n\n   @Override\n   public void handle(ChannelHandlerContext ctx, HttpPackage httpPacket) {\n      final List\u003cGenealogy\u003e genealogies = genealogyService.listAll();\n      //System.out.println(\"genealogies = \" + genealogies);\n      responseJson(ctx, httpPacket, genealogies);\n      forward2insideServerUseSender(\n              NetworkPacket.Builder.withDefaultHeader()\n                      .msgType(100).writeStr(genealogies.toString()),\n              \"hall\",\n              \"\",3);\n      QueueMessageSender.publish(\"hall\", \"test\", genealogies.toString());\n   }\n\n   @Override\n   public Object threadKey(ChannelHandlerContext ctx, NetworkPacket.Decoder decoder) {\n      return null;\n   }\n}\n```\n\n* The stress test tool is `jmeter`, and the configuration is as follows\n\n![images](docs/test/threadGroup.png)\n---\n![images](docs/test/httpRequest.png)\n\n* Test result\n\n![images](docs/test/report.png)\n---\n![images](docs/test/repsoneTimeGraph.png)\n\n### NOTE\n\n调试资源泄露，启动时添加：-Xms12m -Xmx12m -Dio.netty.leakDetection.level=paranoid\n\n### TODO LIST\n\n1. ~~内网不同协议的转发~~\n2. ~~外网消息转发到内网处理器中~~\n3. ~~外部用户登录~~\n4. ~~用户消息内网转发~~\n5. ~~用户消息外网转发~~\n6. ~~群组消息内网转发~~\n7. ~~群组消息外网转发~~\n8. ~~serverType写在framework中需要解决~~\n9. ~~服务端、客户端消息转发待测试~~\n10. ~~延迟线程池装配，任务执行完之后，处理逻辑~~\n11. ~~http协议抽离~~\n12. ~~完善readme~~\n13. ~~mysql~~、~~mybatis~~、~~redis~~、~~mq等配置~~\n14. ~~本地缓存~~~~，缓存失效时间，缓存失效时，重新查询数据库~~\n15. ~~请求限流~~\n16. ~~内网消息队列和失败重发机制~~，~~添加权重转发机制~~\n17. ~~为避免长时间占用链接，没有登录的链接，服务端添加心跳检测机制，如果超过一定时间没有收到心跳，则主动断开链接~~\n18. ~~外网支持协议配置化~~\n19. ~~内网消息重组~~，~~支持延迟消息~~，~~可靠消息（保证送达与幂等性）~~\n20. ~~分布式事务？~~\n21. ~~内网服务器登录，将已登录的session同步给登录服务器~~\n22. ~~内网服务登出，同步消息给登录服务器~~\n23. ~~用户登录接口抽离由使用框架者实现~~，~~同时还有用户登录内网同步和登出内网同步接口~~\n24. ~~内网消息不可达时，可选路由到相同类型的其他节点~~\n25. 消息转发，重复发送检测\n26. ~~MQTT协议支持？~~\n27. ~~协议头配置化~~？\n28. 注册接口？\n29. ~~接口权限控制？~~\n30. ~~做一个im群组聊天室，测试框架完善度~~\n31. ~~让内部服务客户端发送同步消息（客户端发送等待服务端返回消息）~~\n32. ~~重构NetworkPacket，body部分改成rawBody、extendBody，方便扩展~~\n33. ~~udp协议问题修复，消息体改版后其他模块的适配~~\n34. ~~消息解码时，添加消息体长度校验：java.lang.OutOfMemoryError: Java heap space~~\n35. ~~转发延迟时间单位可选~~","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzunzhuowei%2Fnetwork-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fzunzhuowei%2Fnetwork-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fzunzhuowei%2Fnetwork-server/lists"}