Netty-SocketIO:最好⽤的Java版即时消息推送
Netty-SocketIO是⼀个开源的、基于Netty的、Java版的即时消息推送项⽬。通过Netty-SocketIO,我们可以轻松的实现服务端主动向客户端推送消息的场景,⽐如说股票价格变化、K线图、消息提醒等。它和websocket有相同的作⽤,只不过Netty-SocketIO可⽀持所有的浏览器。
Socket.IO除了⽀持WebSocket通讯协议外,还⽀持许多种轮询(Polling)机制以及其它实时通信⽅式,并封装成了通⽤的接⼝,并且在服务端实现了这些实时机制的相应代码。Socket.IO实现的Polling通信机制包括Adobe Flash Socket、AJAX长轮询、AJAX multipart streaming、持久Iframe、JSONP轮询等。Socket.IO能够根据浏览器对通讯机制的⽀持情况⾃动地选择最佳的⽅式来实现⽹络实时应⽤。
###⼀、下载Netty-SocketIO
1. socket.io-client-master
2. netty-socketio-master
3. netty-socketio-demo-master
从netty-socketio的git上可下载到以上三个压缩包,分别对应的是web 客户端的所需⽂件、netty socketio的java服务端实现、以及对应的可以应⽤web推送的demo。
###⼆、部署server的资源项⽬
从git上下载的socketio server压缩包中没有项⽬所需的jar包,我是⾃⼰新建了⼀个项⽬,本来上传到了CSDN的代码库⾥了,但写博客的时候怎么也打不开了,那么只能提供对应项⽬导航图,同时提供jar包的下载地址,需要的可动⼿去获得。
然后将jar包添加到项⽬中。
切记jdk的版本⼀定要在1.7以上,我在本地环境中⽤的1.7,但是服务器上⼀直⽤的是1.6,部署项⽬的
时候没有注意,导致服务端可以接收到客户端的socketio 的connect,但是客户端的response相应中却连接不通,开始的时候以为是跨域问题导致的,搜了好多帖⼦,但问题根本就是不是跨域引起的,jdk的版本换成1.7就ok了,因为netty的nio是基于java的1.7的。
###三、应⽤server
在需要应⽤socketio的项⽬上右键,为项⽬添加socketio项⽬⽀持(注意红⾊标出的)。
新建main类。
public static void main(String[] args)throws InterruptedException {
Configuration config =new Configuration();
config.setHostname("localhost");
config.setPort(10015);
SocketIOServer server =new SocketIOServer(config);
server.addConnectListener(new ConnectListener(){// 添加客户端连接
@Override
public void onConnect(SocketIOClient client){
logger.RemoteAddress()+" web客户端接⼊");
client.sendEvent("helloPush","hello");
}
});
/
/ 握⼿请求
server.addEventListener("helloevent", HelloUid.class,new DataListener<HelloUid>(){
@Override
public void onData(final SocketIOClient client, HelloUid data, AckRequest ackRequest){
// 握⼿
Message().equals("hello")){
int userid = Uid();
logger.info(Thread.currentThread().getName()+"web读取到的userid:"+ userid);
// send message back to client with ack callback
// WITH data
client.sendEvent("hellopush",new AckCallback<String>(String.class){
@Override
public void onSuccess(String result){
logger.info("ack from client: "+ SessionId()+" data: "+ result);
}
}, sessionTime);
}else{
logger.info("⾏情接收到了不应该有的web客户端请求");
}
}
});
server.start();
Thread.sleep(Integer.MAX_VALUE);
server.stop();
}
当client通过ip和端⼝连接到server后,会构造⼀个SocketIOClient client的对象,在实际的应⽤中,可以将该client保存起来,通过client.sendEvent("helloPush", "hello");就可以向client端发送相应的数据了。
###四、应⽤client
####①、引⼊socket.io.js
<script type="text/javascript" src="${ctx}/components/socketio/socket.io.js"></script>
####②、创建connection的公共⽅法
function connectQuotation(uid, callback){
// 链接⾏情server
socket = io.connect('localhost:10015');
// 如果⽤户在web端登陆,那么发送握⼿请求
if(uid){
// 连接上server后
<('connect',function(){
// 发送握⼿请求
var jsonObject ={
uid :parseInt(uid),
message :"hello"
};
<('hellopush',function(data, ackServerCallback, arg1){
// base64转码的数据,可忽视
YUNM.session ={
sessionId : $.base64.atob(data.sessionId),
time : $.base64.atob(data.time)
};
if(ackServerCallback){
ackServerCallback('server message was delivered to client!');
}
});
});
}
// 如果web端session超时,socket断开,10分钟扫描⼀次
int = window.setInterval(function(){
// 我是通过ajax判断session超时的,你也可以通过其他⽅式
$.ajax({
type :'POST',
url : +"/getSessionTimeout",
dataType :"json",
cache :false,
success :function(json){
var timeout =ssage);
/
/ session超时后,socket断开,服务端就可以监听到释放资源
if(timeout ==0){
socket.disconnect();
}
},
error :function(){
socket.disconnect();
// 清除
window.clearInterval(int);
}
});
},YUNM._set.interval);
callback();
}
####③、需要web推送的页⾯进⾏socketio的连接
$(function(){
jdk怎么使用
connectQuotation($("#global_uid").val(),function(){
<("pushQuotation",function(message){
pe =="dealOrder"){
var msg = sult;
// 输出服务端消息
YUNM.debug(msg);
}
});
});
});
###五、注意事项
1. 关于socketio的ssl应⽤,⼀直没有弄出来,主要是java的toolkey⽣成的jks总是不被浏览器识别,socketio提供的例⼦也不能运⾏,
在各⼤⽹站上暂时没有解决问题。可通过浏览器添加https的例外做法来规避错误,但不可取,后⾯还需要研究。
2. socketio在浏览器刷新后,旧的连接断开,需要重新建⽴连接,这个请注意。
3. 客户端session超时后,切记关闭socket,我是通过10分钟⼀次的扫描进⾏的session超时验证,该⽅法不够理想。
4. server端,在实际应⽤中,需要将客户端断开的socket进⾏垃圾清理,注意判断⽅法如下:
NamespaceClient client =(NamespaceClient) socket;
BaseClient().isConnected()){
}else{
logger.warn("web发送⼼跳包失败,客户端连接线程["+Name()+"]已断开");
running =false;
break;
}
整体Netty-SocketIO的Web推送还是⾮常易于掌握的,但是缺少api,做起来需要不停实践,另外解决问题的⽅法不多,希望本篇可以给你提供些许帮助。
2017年12⽉26⽇补充:
项⽬迁移到了另外⼀台阿⾥云服务器,于是Netty-SocketIO的server在启动的时候出现了以下错误:
java.BindException: Cannot assign requested address: bind
at sun.nio.ch.Net.bind0(Native Method)
at sun.nio.ch.Net.bind(Unknown Source)
at sun.nio.ch.Net.bind(Unknown Source)
at sun.nio.ch.ServerSocketChannelImpl.bind(Unknown Source)
at ioty.channel.socket.nio.NioServerSocketChannel.doBind(NioServerSocketChannel.java:127)
问题发⽣在server.start()处,进⾏javaChannel().bind(localAddress, Backlog());域名和端⼝绑定时出现了错误:
private SocketIOServer server = null;
server =new WebQuotationConfig());// 此处的Configuration对象的Hostname设置的是域名,Port设置为10015 server.start();
最开始从⽇志⾥⾯出了这样⼀条消息:
socketio.SocketIOServer$1: SocketIO server start failed at port: 10015!
直觉告诉我,阿⾥云的安全组在作怪,把10015端⼝禁掉了。于是我就去改安全组,把10015的⼊⽅向和出⽅向都放开了,但问题依然没有解决。
接下来,我只能丈⼆和尚摸不着头脑的去百度,他娘的结果没什么可靠的信息,都是⼀些乱七⼋糟的东西——什么端⼝被占⽤,使⽤netstat -ano查询端⼝,还有什么hosts⽂件要修改,等等,⼀系列坑爹⼜不负责任的答案。
折腾了接近四个半⼩时的时间,我™⼏乎要疯了,脑⼦⼀股热⾎升腾,恨不得把⿏标给砸了。
在⽓晕的状态下,我努⼒的控制着⾃⼰,问:“明明上⼀台阿⾥服务器的时候,这样配置,socketio就是正常的,现在怎么™就error 了?”
试着让⾃⼰恢复冷静,就能想到办法。“不是端⼝的问题,那肯定是域名的问题!”
我试了试“localhost”,发现SocketIOServer竟然start成功了这说明什么问题,说明域名没有localhost的权限!但改成localhost有⽑⽤,客户端不可能访问到服务器的localhost啊?
接着,我想到了IP地址把域名换成公⽹的IP地址,竟然™的SocketIOServer start成功了!!!!
此时有两种解决⽅案,⼀是使⽤IP来替代域名,另外⼀个就是继续域名的解决⽅案——⼀个不懂⽹络的程序员注定在⽹络安全⽅⾯吃点亏!,我™就是受害者之⼀。
好了,问题记录就先到这⾥——解决问题的最好办法就是让⾃⼰冷静下来
2018年9⽉11⽇补充:
由于项⽬在tomcat服务器的访问前缀由原来的http改为https,导致客户端的socketio⽆法正常访问到Netty-SocketIO服务器端。从昨天到今天,整整两天,⼀直在寻解决⽅案,现在事情终于有所转机,为了更多⼩伙伴的需要,就把问题整理备案。
有了jks,我们可以先将Server端升级到https,也就是ssl(⾮常抱歉,对https和ssl我还不是很清楚,但并不妨碍我将实例运⾏起来)。
Configuration config = new Configuration();
config.setPort(10015);
// 注意不要指定config.setHostname
// 具体原因不清楚,不得不再说⼀声抱歉,我在⽹络⽅⾯就是⼀个⽩痴,⽐如说我不懂hosts⽂件是⼲嘛的,也不懂内⽹和外⽹之间的区别,总之这⼀块使我⾮常焦虑,只好⼀步步组合⽅案进⾏试验,换句话说理论知识不够,只能靠不断试错来总结经验
// keystore.jks的密钥
config.setKeyStorePassword("test1234");
InputStream stream = new FileInputStream(new File("/home/soft/keystore.jks"));
config.setKeyStore(stream);
// 升级为https
server = new SocketIOServer(config);
然后我们来看客户端
var socket =  io.connect('147.101.128.223:10015');
// 使⽤https⽽不再是http,然后紧接着是服务器的外⽹地址,不知道为什么,然后是对应的端⼝
现在,已经可以通过https来访问到socketio的服务器端了。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。