{"id":20917552,"url":"https://github.com/impact-eintr/nettychatroom","last_synced_at":"2025-07-10T01:41:15.226Z","repository":{"id":107515179,"uuid":"398936431","full_name":"impact-eintr/NettyChatRoom","owner":"impact-eintr","description":"netty写的小聊天室","archived":false,"fork":false,"pushed_at":"2021-08-23T03:18:43.000Z","size":17,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-01-19T16:48:09.150Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/impact-eintr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2021-08-23T01:10:04.000Z","updated_at":"2021-10-21T02:04:25.000Z","dependencies_parsed_at":"2023-05-17T15:45:30.673Z","dependency_job_id":null,"html_url":"https://github.com/impact-eintr/NettyChatRoom","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2FNettyChatRoom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2FNettyChatRoom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2FNettyChatRoom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/impact-eintr%2FNettyChatRoom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/impact-eintr","download_url":"https://codeload.github.com/impact-eintr/NettyChatRoom/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":243311891,"owners_count":20271064,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":[],"created_at":"2024-11-18T16:34:10.710Z","updated_at":"2025-03-12T23:29:36.901Z","avatar_url":"https://github.com/impact-eintr.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NettyChatRoom 开发文档\n\n用netty 开发为的是它的高性能和封装性(原生Socket写吐了, netty的对象序列化真香) \n## 通讯协议\n- Message.java 实现了 Serializable 接口 以序列化\n  - messageType 数据类型 现在实现的有登陆和聊天\n  - squenceId 数据编号 保留接口后续可以用于记录消息顺序(你懂的)\n  - getMessageType() 获取数据类型 子类必须要重写这个方法\n  \n- AbstractResponseMessage Message的抽象子类 作为所有响应消息的父类\n  - success 是否成功响应\n  - reason 失败原因\n  ``` java\n  public AbstractResponseMessage(boolean success, String reason) {\n    this.success = success;\n    this.reason = reason;\n  }\n  ```\n\u003e 请求\n- LoginRequestMessage Message的子类 \n  - username\n  - password\n- ChatRequestMessage\n  - from 消息来自\n  - to 消息发往\n  - content 消息内容\n  \n\u003e 响应\n- LoginResponseMessage AbstractResponseMessage的子类 响应登陆消息\n- ChatResponseMessage AbstractResponseMessage的子类 响应聊天消息\n  - from 消息来自\n  - content 消息内容\n## 服务端\n``` java\npublic class SimpleChatServer {\n\n\tprivate int port;\n\n\tpublic SimpleChatServer(int port) {\n\t\tthis.port = port;\n\t}\n\n\tpublic void run() throws Exception {\n\n\t\tEventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)\n\t\tEventLoopGroup workerGroup = new NioEventLoopGroup();\n\t\ttry {\n\t\t\tServerBootstrap b = new ServerBootstrap(); // (2)\n\t\t\tb.group(bossGroup, workerGroup)\n\t\t\t\t\t\t\t.channel(NioServerSocketChannel.class) // (3)\n\t\t\t\t\t\t\t.childHandler(new SimpleChatServerInitializer())  //(4)\n\t\t\t\t\t\t\t.option(ChannelOption.SO_BACKLOG, 128)          // (5)\n\t\t\t\t\t\t\t.childOption(ChannelOption.SO_KEEPALIVE, true); // (6)\n\n\t\t\tSystem.out.println(\"SimpleChatServer 启动了\");\n\n\t\t\t// 绑定端口，开始接收进来的连接\n\t\t\tChannelFuture f = b.bind(port).sync(); // (7)\n\n\t\t\t// 等待服务器  socket 关闭 。\n\t\t\t// 在这个例子中，这不会发生，但你可以优雅地关闭你的服务器。\n\t\t\tf.channel().closeFuture().sync();\n\n\t\t} finally {\n\t\t\tworkerGroup.shutdownGracefully();\n\t\t\tbossGroup.shutdownGracefully();\n\n\t\t\tSystem.out.println(\"SimpleChatServer 关闭了\");\n\t\t}\n\t}\n\n\tpublic static void main(String[] args) throws Exception {\n\t\tint port;\n\t\tif (args.length \u003e 0) {\n\t\t\tport = Integer.parseInt(args[0]);\n\t\t} else {\n\t\t\tport = 6430;\n\t\t}\n\t\tnew SimpleChatServer(port).run();\n\n\t}\n}\n\n```\n### 服务端的总体流程:\n- 建立连接\n- 注册处理函数，等待客户端的访问\n- 在成功建立与客户端后的链接后，会得到用户发来的登陆消息LoginRequestMessage(至于这些怎么验证 由于时间仓促没有实现 可以用数据库存储 然后保存在一个全局的map中 来保证用户登陆的唯一性)\n- 构建LoginResponseMessage\n- 获取ChatRequestMessage 解包消息（这里其实可以进行数据处理 比如@功能 敏感词处理等, 这里不做特殊处理）\n- 构建ChatResponseMessage 发送消息时 服务端不会区分谁是谁 这个任务由客户端进行（通过解析协议 可以获取From） 可以提高一点服务端的性能\n\n\n## 客户端\n```java\npublic class SimpleChatClient {\n\tpublic static void main(String[] args) throws Exception{\n\t\tnew SimpleChatClient(\"localhost\", 6430).run();\n\t}\n\n\tprivate final String host;\n\tprivate final int port;\n\n\tpublic SimpleChatClient(String host, int port){\n\t\tthis.host = host;\n\t\tthis.port = port;\n\t}\n\n\tpublic void run() throws Exception{\n\t\tEventLoopGroup group = new NioEventLoopGroup();\n\t\ttry {\n\t\t\tBootstrap bootstrap  = new Bootstrap()\n\t\t\t\t\t\t\t.group(group)\n\t\t\t\t\t\t\t.channel(NioSocketChannel.class)\n\t\t\t\t\t\t\t.handler(new SimpleChatClientInitializer());\n\t\t\tChannel channel = bootstrap.connect(host, port).sync().channel();\n\n\t\t\t// 获取用户输入\n\t\t\tBufferedReader in = new BufferedReader(new InputStreamReader(System.in));\n\t\t\twhile(true){\n\t\t\t\tSystem.out.println(\"==================================\");\n\t\t\t\tSystem.out.println(\"send [content]\");\n\t\t\t\tSystem.out.println(\"quit\");\n\t\t\t\tSystem.out.println(\"==================================\");\n\t\t\t\tString command = in.readLine();\n\t\t\t\tString[] s = command.split(\" \");\n\t\t\t\tswitch (s[0]){\n\t\t\t\t\tcase \"send\":\n\t\t\t\t\t\tif (s.length != 2) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tChatRequestMessage msg = new ChatRequestMessage(\n\t\t\t\t\t\t\t\t\t\tchannel.localAddress().toString(),\n\t\t\t\t\t\t\t\t\t\tchannel.remoteAddress().toString(),\n\t\t\t\t\t\t\t\t\t\ts[1]);\n\t\t\t\t\t\tchannel.writeAndFlush(msg);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase \"quit\":\n\t\t\t\t\t\tchannel.close();\n\t\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} catch (Exception e) {\n\t\t\te.printStackTrace();\n\t\t} finally {\n\t\t\tgroup.shutdownGracefully();\n\t\t}\n\n\t}\n}\n```\n### 客户端的总体流程\n- 建立连接 \n- 注册处理函数 \n- 在成功建立与服务器的链接时（处于“激活”状态，可以这个时候获取用户输入 帐号 密码 ）\n- 然后解析服务端返回的信息 判断是否成功登陆\n- 然后用户可以选择聊天或者退出\n- 发送消息时 服务端不会区分谁是谁 这个任务由客户端进行（通过解析协议 可以获取From） 可以提高一点服务端的性能\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimpact-eintr%2Fnettychatroom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fimpact-eintr%2Fnettychatroom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fimpact-eintr%2Fnettychatroom/lists"}