(原)

往常前后端通讯基本都是以ajax请求或是表单做数据交互的,这是一种无状态的http协议,如果要做tcp协议的数据交互,能想到的技术也就socket了,可如果后端是JAVA,前端如何做socket呢,在html5出来之前,只能用ajax轮询,html5中有定义了一个新的数据传输协议,webSocket,这是一种长连接协议,类似于socket,html5出来好些年了,基本主流浏览器的最新版本都支持,在js中用window.WebScoket就可以得到它,它的API很简单,这里暂不介绍,这里介绍一下对其封装的一个第三方js库,socket.io,下面来看看如何实现吧。

1、你必需知道socket.io实际上就是一个js文件,它可以在这下载。(https://github.com/socketio/socket.io-client

上面也写的很清楚了,最简单的使用方法,也就几行代码。

2、你需要知道JAVA端怎么写最方便,实现已经有第三方针对于socket.io完成了JAVA端的实现,只用引入JAR包,调用相应的API就行了,它跟socket.io有个相对应的名字,叫netty-socketio。它可以在这里下载。(https://github.com/mrniko/netty-socketio

它的文档里也写了一大堆,实际上你如果要最快的上手,只需要这一句话就够了。

netty-socketio的1.6.6版本支持socket.io1.0以下的版本,最新版的netty-socketio支持1.0以上的socket.io版本。

(别混了概念,netty-socketio指的是JAVA端的一个JAR,socket.io指的是一个JS文件)

3.这里就以最新版本以例。

先写前端。

<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>demo</title>
<script src="js/jquery/jquery-1.8.3.min.js" type="text/javascript"></script>
<script type="text/javascript" src="js/socket.io/socket.io.js"></script> </head>
<body> </body>
<script type="text/javascript">
//创建TCP连接
var socket = io.connect('http://192.168.0.104:8998');
//连接成功后会监听到
socket.on('connect',function() {
output('<span>连接成功</span>');
}); socket.on('connecting',function() {
output('<span>正在连接...</span>');
}); socket.on('disconnect',function() {
output('<span>断开连接! </span>');
}); socket.on('reconnecting',function() {
output('<span>正在重连...</span>');
}); socket.on('reconnect',function() {
output('<span>成功重连!</span>');
}); socket.on('connect_failed',function() {
output('<span>连接失败!</span>');
}); //想要断开连接调用此方法
function sendDisconnect() {
socket.disconnect();
}
//下面的testMessage是自定义的。
socket.emit('testMessage', 'Hello',function(){
output('<span>' + data + '</span>');
});
//socket.emit('testMessage', '你好',function(){
// output('<span>' + data + '</span>');
//});
//这里是监听服务端返回的testMessage事件
//socket.on('testMessage',function(data){
// output('<span>' + data + '</span>');
//}); function output(message) {
var currentTime = "<span class='time' >" + new Date().toLocaleString() + "</span>";
var element = $("<div>" + currentTime + " " + message + "</div>");
$('body').prepend(element);
} </script>
</html>

  

  我们叫这个页面为demo.html

然后再写JAVA后端

只需要二个类,一个是开启socket服务的类,一个是监听的类,这里只监听客户端的连接,断开和发送testMessage消息。

package com.ewin.ccr;

import com.corundumstudio.socketio.AckRequest;
import com.corundumstudio.socketio.SocketIOClient;
import com.corundumstudio.socketio.SocketIOServer;
import com.corundumstudio.socketio.listener.ConnectListener;
import com.corundumstudio.socketio.listener.DataListener;
import com.corundumstudio.socketio.listener.DisconnectListener; public class SocketListener implements ConnectListener ,DisconnectListener,DataListener<String>{
private SocketIOServer server; public SocketListener(SocketIOServer server){
this.server = server;
} @Override
public void onConnect(SocketIOClient client) {
Integer clientSize = server.getAllClients().size();
System.out.println("刚连上一个客户端,总共有" + clientSize + "客户端连接成功。");
} @Override
public void onDisconnect(SocketIOClient client) {
Integer clientSize = server.getAllClients().size();
System.out.println("刚离开一个客户端,总共有" + clientSize + "客户端连接成功。");
} @Override
public void onData(SocketIOClient client, String data, AckRequest ackSender)
throws Exception {
System.out.println("刚有一个数据从客户端过来" + data);
ackSender.sendAckData("服务端消息收到!-----");
} }

 以上为监听类

package com.ewin.ccr;

import com.corundumstudio.socketio.Configuration;
import com.corundumstudio.socketio.SocketIOServer;
import com.ewin.ccr.util.SocketConfig; public class SocketServer { public static void main(String[] args) {
Configuration config = new Configuration();
config.setHostname(SocketConfig.getValue("host"));
config.setPort(Integer.parseInt(SocketConfig.getValue("port")));
SocketIOServer server = new SocketIOServer(config); SocketListener socketListener = new SocketListener(server); //客户端连接上时触发
server.addConnectListener(socketListener); //监听客户端消息
//工单产品执行监控表头数据,只发一次,需要由客户端请求后发送
server.addEventListener("testMessage", String.class, new socketListener()); //客户断连接断开时触发
server.addDisconnectListener(socketListener);
//启动服务
server.start(); // server.stop();
}
}

以上为开启socket服务的类

运行SocketServer这个类

然后进入我们的demo页面,你会看到如下信息

后台会是这样的。

然后我们尝试关闭页面。后台会变成这样。

我们尝试关掉JAVA服务,页面会变成这样。

其实,这还没完,这里不知是BUG,还是什么原因,会有一个问题。

看到页面这个地方没有

现在我们来换一下,发送一个中文的"你好"给后台,我们需要把上面的注释取消,把下面的注释放开,改成这样

然后我们把demo.html页面刷新一下,关掉,再重开(这样是为了使修改的JS生效)

OK,前面没有问题,再看下我们的二个中文字“你好”过去没有。

看到没,后端是乱码,估计这种问题的第一反应,可能绝大数程序员想的跟我一样,转码出了问题,于是各种前后端编码,字符集的检查,但是你会发现,以前出现这种问题时,能用上的转码,切换字符集的招数都用遍了, 这里依然无效。

经过我一天的摸索,得到一个好消息与一个坏消息。

先说坏的,百度有人说是socket.io版本不够新,今天是2017年6月4号,最新版是6月2号的2.0.2版本,我试了一下最新的,问题依然存在。

好消息是我找到了问题的解决办法,但是过于暴力。

看下面这段代码:

跟刚才的本质没有变,只是延迟0.5秒发送消息,我们再次刷新demo.html页面,来看下后台的反应。

看到没,中文传送过来了。

那有人可能就要问了,如果做一个即时通讯之类的,那岂不是每次发送消息都要等上半秒钟,其实不是这样的,经过我多次的测试,只有在连接刚建立完成以后的一小段时间内发送中文才会有这个问题(上面其实是连建立后等了0.5秒发送的消息,实际上测的是延迟0.2秒以上再发送消息 ,后面收到中文的概率已经很大了),后面再发送都不会有这个问题。

html面页与JAVA通过webSocket 通讯的更多相关文章

  1. Java用WebSocket + tail命令实现Web实时日志

    原文:http://blog.csdn.net/xiao__gui/article/details/50041673 在Linux操作系统中,经常需要查看日志文件的实时输出内容,通常会使用tail - ...

  2. java 实现websocket

    最近了解了下websocket和socket这个东西,说不得不来说下为何要使用 WebSocket ,和为何不用http. 为何需要WebSocket ? HTTP 协议是一种无状态的.无连接的.单向 ...

  3. websocket通讯协议(10版本)简介

    前言: 工作中用到了websocket 协议10版本的,英文的协议请看这里: http://tools.ietf.org/html/draft-ietf-hybi-thewebsocketprotoc ...

  4. Java和WebSocket开发网页聊天室

    小编心语:咳咳咳,今天又是聊天室,到现在为止小编已经分享了不下两个了,这一次跟之前的又不大相同,这一次是网页聊天室,具体怎么着,还请各位看官往下看~ Java和WebSocket开发网页聊天室 一.项 ...

  5. Java 线程间通讯(管道流方式)

    一.管道流是JAVA中线程通讯的常用方式之一,基本流程如下: 1)创建管道输出流PipedOutputStream pos和管道输入流PipedInputStream pis 2)将pos和pis匹配 ...

  6. Java 线程间通讯(共享变量方式)

    Java线程间通讯,最常用的方式便是共享变量方式,多个线程共享一个静态变量就可以实现在线程间通讯,但是这需要注意的就是线程同步问题. 一.没考虑线程同步: package com.wyf; publi ...

  7. 基于Java的WebSocket推送

    WebSocket的主动推送 关于消息推送,现在的解决方案如轮询.长连接或者短连接,当然还有其他的一些技术框架,有的是客户端直接去服务端拿数据. 其实推送推送主要讲的是一个推的概念,WebSocket ...

  8. webSocket通讯

    1.使用facebook第三方SRWebSocket进行websocket通讯. pod 'SocketRocket' 2.通讯地址: ws://192.168.1.128:18882/ws 注意:s ...

  9. java 实现websocket的三种方式

    Java中实现websocket常见有以下三种方式: 使用tomcat的websocket实现,需要tomcat 7.x,JEE7的支持. 使用spring的websocket,spring与webs ...

随机推荐

  1. [leetcode](4.21)1. 有序数组中的缺失元素

    给出一个有序数组 A,数组中的每个数字都是 独一无二的,找出从数组最左边开始的第 K 个缺失数字. 示例 1: 输入:A = [4,7,9,10], K = 1 输出:5 解释: 第一个缺失数字为 5 ...

  2. 【Java每日一题】20170315

    20170314问题解析请点击今日问题下方的“[Java每日一题]20170315”查看(问题解析在公众号首发,公众号ID:weknow619) package Mar2017; public cla ...

  3. Java五种基本的Annotation,提高程序的可读性

    从JDK5开始,Java增加了对元数据的支持,也就是Annotation(即注解也被翻译为注释). 这里的Annotation和普通的注释有一定的区别,它是代码中的特殊标记,这些标记可以在编译.类加载 ...

  4. Java中单例实现

    1:.经典懒汉: 代码如下: package org.pine.test; public class Person { private String name; private int age; pu ...

  5. 8;XHTML 框架

    1.多窗框的基本结构 2.嵌套多窗体设置 3.多框架与超链接 4.悬浮窗体的设置 浏览器视窗本身就是一个框架,网页就是显示在该单 一的框架内,本章将介绍另一种网页呈现的方式,那就是可将原先单一的框架分 ...

  6. jQuery插件开发进阶

    jQuery插件开发模式 软件开发过程中是需要一定的设计模式来指导开发的,有了模式,我们就能更好地组织我们的代码,并且从这些前人总结出来的模式中学到很多好的实践. 根据<jQuery高级编程&g ...

  7. vuejs 1.x - 实例:搜索过滤

    <!DOCTYPE html> <html> <head> <meta name="viewport" content="wid ...

  8. centos 安装mysql Package: akonadi-mysql-1.9.2-4.el7.x86_64 (@anaconda)

    wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm rpm -ivh mysql-community-release ...

  9. Android gradle实现多渠道号打包

    在build.gradle中添加 productFlavors{ LETV { applicationId "×××××××××××" //包名   buildConfigFiel ...

  10. 从头开始:详解MVVM、MVVMLight

    究竟为什么要学习MVVM? 相信大部分同学在刚开始接触MVVM的时候(包括我自己),心里默默在想这究竟是什么玩意?一个简单的功能要写一大段代码才能完成,在看到MVVM的核心目标: 1.让UI界面与逻辑 ...