(原)
往常前后端通訊基本都是以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秒以上再發送消息 ,后面收到中文的概率已經很大了),后面再發送都不會有這個問題。
