{"id":20904528,"url":"https://github.com/luohaha/lightcomm4j","last_synced_at":"2025-10-20T10:38:22.210Z","repository":{"id":57727847,"uuid":"89984344","full_name":"luohaha/LightComm4J","owner":"luohaha","description":"Yet another lightweight asynchronous network library for java","archived":false,"fork":false,"pushed_at":"2017-11-08T11:28:22.000Z","size":60,"stargazers_count":23,"open_issues_count":0,"forks_count":6,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-07-03T00:05:38.460Z","etag":null,"topics":["asynchronous","java","lightweight"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"agpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/luohaha.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}},"created_at":"2017-05-02T02:44:00.000Z","updated_at":"2025-06-30T06:15:25.000Z","dependencies_parsed_at":"2022-08-30T08:31:53.062Z","dependency_job_id":null,"html_url":"https://github.com/luohaha/LightComm4J","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/luohaha/LightComm4J","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2FLightComm4J","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2FLightComm4J/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2FLightComm4J/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2FLightComm4J/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/luohaha","download_url":"https://codeload.github.com/luohaha/LightComm4J/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/luohaha%2FLightComm4J/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":263234943,"owners_count":23434918,"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":["asynchronous","java","lightweight"],"created_at":"2024-11-18T13:17:37.825Z","updated_at":"2025-10-20T10:38:22.112Z","avatar_url":"https://github.com/luohaha.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# LightComm4J\n\nYet another asynchronous network library for java\n\n## Install\n\n\u003eMaven\n\n```java\n\u003cdependency\u003e\n  \u003cgroupId\u003ecom.github.luohaha\u003c/groupId\u003e\n  \u003cartifactId\u003eLightComm4J\u003c/artifactId\u003e\n  \u003cversion\u003e1.0.0\u003c/version\u003e\n\u003c/dependency\u003e\n```\n\n\u003eDownload jar\n\n[download](https://oss.sonatype.org/service/local/repositories/releases/content/com/github/luohaha/LightComm4J/1.0.0/LightComm4J-1.0.0.jar)\n\n## How to use\n\n* server-side\n\nFirst, we need to creates a socket address from a hostname and a port number. And then, we should define some callback function when some event happens. We use `ServerParam` to store these informations.\n\n```java\nServerParam param = new ServerParam(\"localhost\", 8888);\n// set backlog\nparam.setBacklog(128);\nparam.setOnAccept(conn -\u003e {\n\tSystem.out.println(\"accept!\");\n});\nparam.setOnRead((conn, data) -\u003e {\n\tSystem.out.println(\"read!\");\n});\nparam.setOnWrite(conn -\u003e {\n\tSystem.out.println(\"write!\");\n});\nparam.setOnClose(conn -\u003e {\n\tSystem.out.println(\"close!\");\n});\nparam.setOnReadError((conn, err) -\u003e {\n\tSystem.out.println(err.getMessage());\n});\nparam.setOnWriteError((conn, err) -\u003e {\n\tSystem.out.println(err.getMessage());\n});\nparam.setOnAcceptError(err -\u003e {\n\tSystem.out.println(err.getMessage());\n});\n```\n\n`OnAccept` will be called when accepter return a new connection. `OnRead` will be called when socket's recv buffer isn't empty. `OnWrite` will be called at first time when socket's send buffer isn't empty and it will be call just once. When remote side close socket, then `OnClose` be called, but if we close server side socket first, this function will not be called forever.\n\nFinally, we can start our server using 'ServerParam' and need to decide the size of io thread pool.\n\n```java\n// 4 is the io thread pool's size\nLightCommServer server = new LightCommServer(param, 4);\nserver.start();\n```\n\n* client-side\n\nThe usage of client side is similar to server side. First, we also need to create a `ClientParam` which is just like `ServerParam`, and define some callback function in it.\n\n```java\nClientParam param = new ClientParam();\n\nparam.setOnConnection((conn) -\u003e {\n\tSystem.out.println(\"connect!\");\n});\nparam.setOnWrite((conn) -\u003e {\n\tSystem.out.println(\"write\");\n});\nparam.setOnRead((conn, data) -\u003e {\n\tSystem.out.println(\"read\");\n});\nparam.setOnClose((conn) -\u003e {\n\tSystem.out.println(\"close\");\n});\nparam.setOnReadError((conn, err) -\u003e {\n\tSystem.out.println(err.getMessage());\n});\nparam.setOnWriteError((conn, err) -\u003e {\n\tSystem.out.println(err.getMessage());\n});\nparam.setOnConnError(err -\u003e {\n\tSystem.out.println(err.getMessage());\n});\n```\n\n`OnConnection` will be called when connection is built. `OnWrite`, `OnRead` and `OnClose` are as same as server side.\n\nFinally, we can use client to send message.\n\n```java\n// 4 is the io thread pool's size \nLightCommClient client = new LightCommClient(4);\nclient.connect(\"localhost\", 8888, param);\nclient.connect(\"localhost\", 8889, param);\n```\n\n## Interface\n\n* `OnAccept`\n\n```java\npublic interface OnAccept {\n\tpublic void onAccept(Conn connection);\n}\n```\n\n* `OnClose`\n\n```java\npublic interface OnClose {\n\tpublic void onClose(Conn connection);\n}\n```\n\n* `OnConnection`\n\n```java\npublic interface OnConnection {\n\tpublic void onConnection(Conn connection);\n}\n```\n\n* `OnRead`\n\n```java\npublic interface OnRead {\n\tpublic void onRead(Conn connection, byte[] data);\n}\n```\n\n* `OnWrite`\n\n```java\npublic interface OnWrite {\n\tpublic void onWrite(Conn connection);\n}\n```\n\n* `OnConnError`\n\n```java\npublic interface OnConnError {\n\tpublic void onConnError(Exception e);\n}\n```\n\n* `OnAcceptError`\n\n```java\npublic interface OnAcceptError {\n\tpublic void onAcceptError(Exception e);\n}\n```\n\n* `OnReadError`\n\n```java\npublic interface OnReadError {\n\tpublic void onReadError(Conn conn, Exception e);\n}\n```\n\n* `OnWriteError`\n\n```java\npublic interface OnWriteError {\n\tpublic void onWriteError(Conn conn, Exception e);\n}\n```\n\n* `Conn`\n\nWe can send message, close connection and set tcp options by `Conn`.\n\n```java\npublic interface Conn {\n    // send data to remote side\n\tpublic void write(byte[] data) throws ConnectionCloseException, ClosedChannelException;\n    // close connection when nothing to send\n\tpublic void close() throws IOException;\n    // close connection immediately\n\tpublic void doClose() throws IOException;\n    // get local address\n\tpublic SocketAddress getLocalAddress() throws IOException;\n    // get remote address\n\tpublic SocketAddress getRemoteAddress() throws IOException;\n    // set socket's send buffer' size\n\tpublic void setSendBuffer(int size) throws IOException;\n    // set socket's recv buffer' size\n\tpublic void setRecvBuffer(int size) throws IOException;\n    // open keep-alive mode\n\tpublic void setKeepAlive(boolean flag) throws IOException;\n    // open reuse address mode\n\tpublic void setReUseAddr(boolean flag) throws IOException;\n    // no use nagle algorithm\n\tpublic void setNoDelay(boolean flag) throws IOException;\n     // get socket's send buffer' size\n\tpublic int getSendBuffer() throws IOException;\n    // get socket's recv buffer' size\n\tpublic int getRecvBuffer() throws IOException;\n\tpublic boolean getKeepAlive() throws IOException;\n\tpublic boolean getReUseAddr() throws IOException;\n\tpublic boolean getNoDelay() throws IOException;\n}\n```\n\n## How to use rpc\n\n* server-side  \n\nFirst, we need to create `RpcServer`, set host address and port. Then we need to add remote call function's name and `IRpcFunction`. Finally, start server.\n\n```java\nRpcServer rpcServer = new RpcServer(\"localhost\", 8888);\nrpcServer.add(\"add\", new AddRpc());\nrpcServer.start();\n```\n\n```java\npublic class AddRpc implements IRpcFunction{\n    @Override\n    public Object rpcCall(String function, List\u003cObject\u003e params) {\n        int res = (int)params.get(0) + (int)params.get(1);\n        return res;\n    }\n}\n```\n\n* client-side\n\nFirst, we need to create `RpcClient`, then start it. Then we can use `remote` and `call` to finish remote process call.\n\n```java\nRpcClient client = new RpcClient();\n// need to start client, before remote call.\nclient.start();\nclient.remote(\"localhost\", 8888).call(\"add\", 1, 2);\n```\n\n## Example\n\nwe use `LightComm4J` to build a simple chatroom.\n\n* server-side\n\n```java\npublic class ChatRoomServer {\n\tpublic static void main(String[] args) {\n\t\tServerParam param = new ServerParam(\"localhost\", 8888);\n\t\tSet\u003cConn\u003e conns = new HashSet\u003c\u003e();\n\t\tparam.setBacklog(128);\n\t\tparam.setOnAccept(conn -\u003e {\n\t\t\ttry {\n\t\t\t\tString m = conn.getRemoteAddress().toString() + \" \" + \"is online!\";\n\t\t\t\tconns.add(conn);\n\t\t\t\tconns.forEach(c -\u003e {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tc.write(m.getBytes());\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t});\n\t\tparam.setOnRead((conn, msg) -\u003e {\n\t\t\ttry {\n\t\t\t\tString m = conn.getRemoteAddress().toString() + \" : \" + new String(msg);\n\t\t\t\tconns.forEach(c -\u003e {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tc.write(m.getBytes());\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t});\n\t\tparam.setOnClose(conn -\u003e {\n\t\t\ttry {\n\t\t\t\tconns.remove(conn);\n\t\t\t\tString m = conn.getRemoteAddress().toString() + \" \" + \"is offline!\";\n\t\t\t\tconns.forEach(c -\u003e {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tc.write(m.getBytes());\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t} catch (Exception e) {\n\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\te.printStackTrace();\n\t\t\t}\n\t\t});\n\t\tparam.setOnReadError((conn, err) -\u003e {\n\t\t\tSystem.out.println(err.getMessage());\n\t\t});\n\t\tparam.setOnWriteError((conn, err) -\u003e {\n\t\t\tSystem.out.println(err.getMessage());\n\t\t});\n\t\tparam.setOnAcceptError(err -\u003e {\n\t\t\tSystem.out.println(err.getMessage());\n\t\t});\n\t\t\n\t\tLightCommServer server = new LightCommServer(param, 4);\n\t\ttry {\n\t\t\tserver.start();\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n\n```\n\n* client-side\n\n```java\npublic class ChatRoomClient {\n\tpublic static void main(String[] args) {\n\t\tClientParam param = new ClientParam();\n\t\tparam.setOnConnection(conn -\u003e {\n\t\t\tnew Thread(() -\u003e {\n\t\t\t\tScanner scanner = new Scanner(System.in);\n\t\t\t\twhile (scanner.hasNext()) {\n\t\t\t\t\tString msg = scanner.nextLine();\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconn.write(msg.getBytes());\n\t\t\t\t\t} catch (Exception e) {\n\t\t\t\t\t\t// TODO Auto-generated catch block\n\t\t\t\t\t\te.printStackTrace();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}).start();\n\t\t});\n\t\tparam.setOnRead((conn, msg) -\u003e {\n\t\t\tSystem.out.println(\"[chatroom] \" + new String(msg));\n\t\t});\n\t\tparam.setOnClose(conn -\u003e {\n\t\t\tSystem.out.println(\"[chatroom] \" + \"chatroom close!\");\n\t\t});\n\t\ttry {\n\t\t\tLightCommClient client = new LightCommClient(4);\n\t\t\tclient.connect(\"localhost\", 8888, param);\n\t\t} catch (IOException e) {\n\t\t\t// TODO Auto-generated catch block\n\t\t\te.printStackTrace();\n\t\t}\n\t}\n}\n\n```\n\n## Example for RPC\n\n* server\n\n```java\npublic class RpcServerTest {\n    public static void main(String[] args) {\n        RpcServer rpcServer = new RpcServer(\"localhost\", 8888);\n        rpcServer.add(\"add\", new AddRpc());\n        rpcServer.start();\n    }\n}\n```\n\n```java\npublic class AddRpc implements IRpcFunction{\n    @Override\n    public Object rpcCall(String function, List\u003cObject\u003e params) {\n        int res = (int)params.get(0) + (int)params.get(1);\n        return res;\n    }\n}\n```\n\n* client\n\n```java\npublic class RpcClientTest {\n\n    private static RpcClient client = new RpcClient();\n\n    public static int add(int a, int b) {\n        return a + b;\n    }\n\n    public static int addRpc(int a, int b) {\n        return (int)client.remote(\"localhost\", 8888).call(\"add\", a, b);\n    }\n\n    public static void main(String[] args) {\n        client.start();\n        System.out.println(\"1 + 2 = \" + add(1, 2));\n        System.out.println(\"1 + 2 = \" + addRpc(1, 2));\n    }\n\n}\n```","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluohaha%2Flightcomm4j","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fluohaha%2Flightcomm4j","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fluohaha%2Flightcomm4j/lists"}