netty-socketio 示例代码
socket.io是一个不错的websocket项目,github上有它的java实现:netty-socketio 及 示例项目 netty-socketio-demo,基本上看看demo示例项目就能很快上手了,但是demo中的示例代码场景为js做客户端,如果需要在java中连接websocket server,可以参考下面的示例:
一、服务端代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | package com.corundumstudio.socketio.demo.server; import com.corundumstudio.socketio.AckRequest; import com.corundumstudio.socketio.Configuration; import com.corundumstudio.socketio.SocketIOClient; import com.corundumstudio.socketio.SocketIOServer; import com.corundumstudio.socketio.listener.ConnectListener; import com.corundumstudio.socketio.listener.DataListener; import io.socket.client.Socket; /** * Created by yangjunming on 2017/1/13. */ public class DemoSocketServer { public static void main(String[] args) throws InterruptedException { Configuration config = new Configuration(); config.setHostname( "localhost" ); config.setPort( 9092 ); final SocketIOServer server = new SocketIOServer(config); server.addConnectListener( new ConnectListener() { @Override public void onConnect(SocketIOClient client) { String token = client.getHandshakeData().getUrlParams().get( "token" ).get( 0 ); if (!token.equals( "87df42a424c48313ef6063e6a5c63297" )) { client.disconnect(); //校验token示例 } System.out.println( "sessionId:" + client.getSessionId() + ",token:" + token); } }); server.addEventListener(Socket.EVENT_MESSAGE, String. class , new DataListener<String>() { @Override public void onData(SocketIOClient client, String data, AckRequest ackSender) throws Exception { System.out.println( "client data:" + data); server.getBroadcastOperations().sendEvent(Socket.EVENT_MESSAGE, "hi" ); } }); server.start(); Thread.sleep(Integer.MAX_VALUE); server.stop(); } } |
服务端的主要工作,就是添加各种事件的监听,然后在监听处理中,做相应的处理即可。
注:添加事件监听时,如果重复添加监听,会导致事件被处理多次,所以最好在添加事件监听前,先移除之前已经存在的监听,类似下面这样
1 2 | chat1namespace.removeAllListeners(Socket.EVENT_MESSAGE); chat1namespace.addEventListener(Socket.EVENT_MESSAGE, String. class ,... |
二、客户端代码
java连接netty-socketio,还要借助另一个开源项目:socket.io-client-java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | package com.corundumstudio.socketio.demo.client; import io.socket.client.IO; import io.socket.client.Socket; import io.socket.emitter.Emitter; import java.net.URISyntaxException; /** * Created by yangjunming on 2017/1/13. */ public class DemoSocketClient { public static void main(String[] args) throws URISyntaxException, InterruptedException { IO.Options options = new IO.Options(); options.transports = new String[]{ "websocket" }; options.reconnectionAttempts = 2 ; options.reconnectionDelay = 1000 ; //失败重连的时间间隔 options.timeout = 500 ; //连接超时时间(ms) // final Socket socket = IO.socket("http://localhost:9092/?token=123456", options);//错误的token值连接示例 final Socket socket = IO.socket( "http://localhost:9092/?token=87df42a424c48313ef6063e6a5c63297" , options); socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { @Override public void call(Object... args) { socket.send( "hello" ); } }); socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() { @Override public void call(Object... args) { System.out.println( "连接关闭" ); } }); socket.on(Socket.EVENT_MESSAGE, new Emitter.Listener() { @Override public void call(Object... args) { System.out.println( "sessionId:" + socket.id()); for (Object obj : args) { System.out.println(obj); } System.out.println( "收到服务器应答,将要断开连接..." ); socket.disconnect(); } }); socket.connect(); } } |
客户端类似,也是加一些事件监听,然后做相应处理即可。
上面的例子,演示了client向server连接时,如何做基本的连接认证(基于token),以及基本的消息收发。
运行效果:
服务端输出
sessionId:f52e9fa3-6216-4742-87de-3228a74469f9,token:87df42a424c48313ef6063e6a5c63297
client data:hello
客户端输出
sessionId:f52e9fa3-6216-4742-87de-3228a74469f9
hi
收到服务器应答,将要断开连接...
连接关闭
注:框架已经自带了一些预设的事件,见下面的代码片段
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | /** * Called on a successful connection. */ public static final String EVENT_OPEN = "open" ; /** * Called on a disconnection. */ public static final String EVENT_CLOSE = "close" ; public static final String EVENT_PACKET = "packet" ; public static final String EVENT_ERROR = "error" ; /** * Called on a connection error. */ public static final String EVENT_CONNECT_ERROR = "connect_error" ; /** * Called on a connection timeout. */ public static final String EVENT_CONNECT_TIMEOUT = "connect_timeout" ; /** * Called on a successful reconnection. */ public static final String EVENT_RECONNECT = "reconnect" ; /** * Called on a reconnection attempt error. */ public static final String EVENT_RECONNECT_ERROR = "reconnect_error" ; public static final String EVENT_RECONNECT_FAILED = "reconnect_failed" ; public static final String EVENT_RECONNECT_ATTEMPT = "reconnect_attempt" ; public static final String EVENT_RECONNECTING = "reconnecting" ; public static final String EVENT_PING = "ping" ; public static final String EVENT_PONG = "pong" ; |
如果不够的话,可以自行扩展,无非就是一些字符串常量。
三、广播消息隔离
前面的示例,没有"域"的概念,所有连到socket server上的client,如果收发广播的话,全都能收到,如果只希望将消息发到指定的某一"批"用户,可以让这些client归到某个域(或组织机构)里,这样在指定的域范围内广播,只有在这个域内的client才能接受广播,详见下面的示例:(其实变化很小)
server端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | package com.corundumstudio.socketio.demo.server; import com.corundumstudio.socketio.*; import com.corundumstudio.socketio.listener.ConnectListener; import com.corundumstudio.socketio.listener.DataListener; import io.socket.client.Socket; /** * Created by yangjunming on 2017/1/13. */ public class DemoSocketServer { public static void main(String[] args) throws InterruptedException { SocketIOServer server = getServer(); addRoom(server); startServer(server); } private static Configuration getConfig() { Configuration config = new Configuration(); config.setHostname( "localhost" ); config.setPort( 9092 ); return config; } private static void handleConn(SocketIOServer server) { server.addConnectListener( new ConnectListener() { @Override public void onConnect(SocketIOClient client) { String token = client.getHandshakeData().getUrlParams().get( "token" ).get( 0 ); if (!token.equals( "87df42a424c48313ef6063e6a5c63297" )) { client.disconnect(); //校验token示例 } System.out.println( "sessionId:" + client.getSessionId() + ",token:" + token); } }); } private static void addRoom(SocketIOServer server) { final SocketIONamespace chat1namespace = server.addNamespace( "/room1" ); chat1namespace.addEventListener(Socket.EVENT_MESSAGE, String. class , new DataListener<String>() { @Override public void onData(SocketIOClient client, String data, AckRequest ackRequest) { chat1namespace.getBroadcastOperations().sendEvent(Socket.EVENT_MESSAGE, "ack:" + data); } }); } private static SocketIOServer getServer() throws InterruptedException { final SocketIOServer server = new SocketIOServer(getConfig()); handleConn(server); server.addEventListener(Socket.EVENT_MESSAGE, String. class , new DataListener<String>() { @Override public void onData(SocketIOClient client, String data, AckRequest ackSender) throws Exception { System.out.println( "client data:" + data); server.getBroadcastOperations().sendEvent(Socket.EVENT_MESSAGE, "hi" ); } }); return server; } private static void startServer(SocketIOServer server) throws InterruptedException { server.start(); Thread.sleep(Integer.MAX_VALUE); server.stop(); } } |
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | package com.corundumstudio.socketio.demo.client; import io.socket.client.IO; import io.socket.client.Socket; import io.socket.emitter.Emitter; import java.net.URISyntaxException; /** * Created by yangjunming on 2017/1/13. */ public class DemoSocketClient { public static void main(String[] args) throws URISyntaxException, InterruptedException { IO.Options options = new IO.Options(); options.transports = new String[]{ "websocket" }; options.reconnectionAttempts = 2 ; options.reconnectionDelay = 1000 ; //失败重连的时间间隔 options.timeout = 500 ; //连接超时时间(ms) //错误的token值连接示例 // final Socket socket = IO.socket("http://localhost:9092/?token=123456", options); //常规连接 // final Socket socket = IO.socket("http://localhost:9092/?token=87df42a424c48313ef6063e6a5c63297", options); //连接到指定的聊天室 final Socket socket = IO.socket( "http://localhost:9092/room2?token=87df42a424c48313ef6063e6a5c63297" , options); socket.on(Socket.EVENT_CONNECT, new Emitter.Listener() { @Override public void call(Object... args) { socket.send( "hello" ); } }); socket.on(Socket.EVENT_DISCONNECT, new Emitter.Listener() { @Override public void call(Object... args) { System.out.println( "连接关闭" ); } }); socket.on(Socket.EVENT_MESSAGE, new Emitter.Listener() { @Override public void call(Object... args) { System.out.println( "sessionId:" + socket.id()); for (Object obj : args) { System.out.println(obj); } System.out.println( "收到服务器应答,将要断开连接..." ); socket.disconnect(); } }); socket.connect(); } } |
注意上面连接时,room1的指定,其它就不多说了,代码就是最好的注释:)
出处:http://yjmyzz.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· Open-Sora 2.0 重磅开源!
2016-01-13 bash/shell编程学习(2)
2013-01-13 MAC本遭遇ARP攻击的处理办法
2010-01-13 windows 2008 使用注意事项