socket.io是一个不错的websocket项目,github上有它的java实现:netty-socketio 及 示例项目 netty-socketio-demo,基本上看看demo示例项目就能很快上手了,但是demo中的示例代码场景为js做客户端,如果需要在java中连接websocket server,可以参考下面的示例:

一、服务端代码

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();
} }

服务端的主要工作,就是添加各种事件的监听,然后在监听处理中,做相应的处理即可。

注:添加事件监听时,如果重复添加监听,会导致事件被处理多次,所以最好在添加事件监听前,先移除之前已经存在的监听,类似下面这样

        chat1namespace.removeAllListeners(Socket.EVENT_MESSAGE);
chat1namespace.addEventListener(Socket.EVENT_MESSAGE, String.class,...

  

二、客户端代码

java连接netty-socketio,还要借助另一个开源项目:socket.io-client-java

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
收到服务器应答,将要断开连接...
连接关闭

注:框架已经自带了一些预设的事件,见下面的代码片段

    /**
* 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端:

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();
} }

客户端:

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的指定,其它就不多说了,代码就是最好的注释:)

netty-socketio 示例代码的更多相关文章

  1. 基于DotNetOpenAuth的OAuth实现示例代码: 获取access token

    1. 场景 根据OAuth 2.0规范,该场景发生于下面的流程图中的(D)(E)节点,根据已经得到的authorization code获取access token. 2. 实现环境 DotNetOp ...

  2. 0038 Java学习笔记-多线程-传统线程间通信、Condition、阻塞队列、《疯狂Java讲义 第三版》进程间通信示例代码存在的一个问题

    调用同步锁的wait().notify().notifyAll()进行线程通信 看这个经典的存取款问题,要求两个线程存款,两个线程取款,账户里有余额的时候只能取款,没余额的时候只能存款,存取款金额相同 ...

  3. ActiveMQ笔记(1):编译、安装、示例代码

    一.编译 虽然ActiveMQ提供了发布版本,但是建议同学们自己下载源代码编译,以后万一有坑,还可以尝试自己改改源码. 1.1 https://github.com/apache/activemq/r ...

  4. C#微信公众平台接入示例代码

    http://mp.weixin.qq.com/wiki/17/2d4265491f12608cd170a95559800f2d.html 这是微信公众平台提供的接入指南.官网只提供了php的示例代码 ...

  5. 编译opengl编程指南第八版示例代码通过

    最近在编译opengl编程指南第八版的示例代码,如下 #include <iostream> #include "vgl.h" #include "LoadS ...

  6. 股票数据调用示例代码php

    <!--?php // +---------------------------------------------------------------------- // | JuhePHP ...

  7. php示例代码之类似于C#中的String.Format方法

    php示例代码之类似于C#中的String.Format方法 原文来自于  http://stackoverflow.com/questions/1241177/c-string-format-equ ...

  8. redis 学习笔记(2)-client端示例代码

    redis提供了几乎所有主流语言的client,java中主要使用二种:Jedis与Redisson 一.Jedis的使用 <dependency> <groupId>redi ...

  9. 正则表达式学习笔记(附:Java版示例代码)

    具体学习推荐:正则表达式30分钟入门教程 .         除换行符以外的任意字符\w      word,正常字符,可以当做变量名的,字母.数字.下划线.汉字\s        space,空白符 ...

随机推荐

  1. CSS-3 文字阴影—text-shadow 的使用

    text-shadow还没有出现的时候,大家在网页中的阴影就是用ps一张图片作为背景.那么现在有了CSS3的这个属性,日后我们的工作会更简洁些. text-shadow之前出现过,不过不久就被Pass ...

  2. 【LibreOJ】#6354. 「CodePlus 2018 4 月赛」最短路 异或优化建图+Dijkstra

    [题目]#6354. 「CodePlus 2018 4 月赛」最短路 [题意]给定n个点,m条带权有向边,任意两个点i和j还可以花费(i xor j)*C到达(C是给定的常数),求A到B的最短距离.\ ...

  3. [R语言]关联规则2---考虑items之间严格的时序关系

    前面介绍了关联规则1---不考虑用户购买的items之间的时序关系,但在一些情况下用户购买item是有严格的次序关系了,比如在某些休闲游戏中,用户购买了道具A才能购买道具B,且道具A和B只能购买一次, ...

  4. <header><footer>引用

    示例:http://www.w3school.com.cn/html/html_layout.asp

  5. c++刷题(33/100)笔试题1

    笔试总共2小时,三道题,时间挺充裕的,但是最后只做了一道,原因在于自己很浮躁,不审题,不仔细思考.没过的两道都是稍微改一下代码就能过,但是没过就是没过,要引以为戒 题目1: 小W有一个电子时钟用于显示 ...

  6. oracel回收站清理

    从powerdesigner中往oracle中导入表,出现了很多类似“BIN$Z35FPY7eFZDgUKjAC94NkA==$0 ”这样的表名, 原因是删除表的时候没有彻底的删除表,而是把表放入回收 ...

  7. oracle中使用sql语句生成10w条测试数据

    sql语句 create table AAAATest as select rownum as cardNo, 'test' creator, to_char(sysdate + rownum//, ...

  8. 如何使用windows的计划任务?计划任务?

    我们经常有一些程序想要过了几小时来运行:比如定时关机 或者说希望能够每天的几点执行一个什么程序: 这些所有的操作都需要用到windows的任务计划:或者叫计划任务:反正都一样 下面小编将指导大家创建一 ...

  9. 一次“ora-12170 tns 连接超时”的经历

      win7    64位系统 oracle  10g   64位 plsql之前连接是好使的,突然连接不上,提示错误“ora-12170 tns 连接超时” 1.ping IP    没有问题 2. ...

  10. Java中final关键字概述

    使用final修饰过的变量都不可以改变: 1.final修饰变量 恒定不变的属性,可以用final关键字来修饰: 变量名建议全部使用大写 final修饰的变量不能改变,如果程序中重新赋值,编译报错 例 ...