WebSocket
WebSocket協(xié)議是基于TCP的一種新的網(wǎng)絡(luò)協(xié)議蔽挠。它實(shí)現(xiàn)了瀏覽器與服務(wù)器全雙工通信————允許服務(wù)器主動(dòng)發(fā)送信息給客戶端住闯。
WebSocket解決了那些問(wèn)題
1,http 是無(wú)狀態(tài),基于請(qǐng)求/響應(yīng)模型澳淑,導(dǎo)致了不識(shí)別用戶比原,每次請(qǐng)求都是一個(gè)新的用戶,
這就產(chǎn)生了cookie,session 記錄用戶的狀態(tài)的技術(shù)杠巡。2量窘,http1.1 進(jìn)行網(wǎng)絡(luò)請(qǐng)求可以重用既有的連接, WebSocket只需進(jìn)行連接一次氢拥。
3蚌铜,向客戶端推送數(shù)據(jù) http輪詢:http的輪詢實(shí)現(xiàn)是客戶端每個(gè)一段時(shí)間就進(jìn)行網(wǎng)絡(luò)請(qǐng)求,
如果服務(wù)器端沒(méi)有數(shù)據(jù)返回也就表示這次請(qǐng)求是無(wú)效的嫩海,多次這樣的網(wǎng)絡(luò)請(qǐng)求會(huì)影響網(wǎng)絡(luò)帶寬厘线,WebSocket是基于tcp全雙工通信,只要連接通道建立出革,服務(wù)器可以向客戶端推送數(shù)據(jù)造壮。4,http 請(qǐng)求包括header 和 要返回的結(jié)果返回給客戶端骂束,往往header大于內(nèi)容的容量,
websoket 瀏覽器和服務(wù)器端會(huì)建立長(zhǎng)連接耳璧,雙方式對(duì)等的,只要發(fā)送數(shù)據(jù)本省展箱,不在需要任何header的信息 旨枯。
netty 服務(wù)器端
- 1,MyServer.java
public class MyServer {
public static void main(String ...arg) throws Exception{
// 負(fù)責(zé)接收客戶端連接
NioEventLoopGroup bossGroup = new NioEventLoopGroup();
// 負(fù)責(zé)處理連接
NioEventLoopGroup wokerGroup = new NioEventLoopGroup();
try{
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup,wokerGroup)
.handler(new LoggingHandler(LogLevel.INFO))
.channel(NioServerSocketChannel.class)
.childHandler(new WebSocketChannelInitializer());
ChannelFuture channelFuture = serverBootstrap.bind(9999).sync();
channelFuture.channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
wokerGroup.shutdownGracefully();
}
}
}
- 2混驰,WebSocketChannelInitializer.java
public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline();
pipeline.addLast(new HttpServerCodec());
pipeline.addLast(new ChunkedWriteHandler());
pipeline.addLast(new HttpObjectAggregator(8192));
//websocket 請(qǐng)求路徑
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
pipeline.addLast(new TextWebSocketFrameHandler());
}
}
- 3,TextWebSocketFrameHandler.java
public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {
System.out.println("服務(wù)器收到:"+msg.text());
ctx.channel().writeAndFlush(new TextWebSocketFrame("服務(wù)器時(shí)間:"+ LocalDateTime.now()));
}
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
//每個(gè)channel 都有一個(gè)唯一的id
System.out.println("handlerAdded: "+ctx.channel().id().asLongText());
}
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("handlerRemoved: "+ctx.channel().id().asLongText());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
}
}
WebSocket js 使用
- 1攀隔,創(chuàng)建對(duì)象
var ws = new WebSocket(url,name);
- 2,發(fā)送文本消息
ws.send(msg);
- 3栖榨,接收消息
ws.onmessage = (function(){...})();
- 4昆汹,錯(cuò)誤處理
ws.onerror = (function(){...})();
- 5,關(guān)閉連接
ws.close();
客戶端端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>websoket 客戶端</title>
</head>
<body>
<form onsubmit="return false">
<textarea name="message" style="width:400px;height: 200px"></textarea>
<input type="button" value="發(fā)送數(shù)據(jù)" onclick="send(this.form.message.value)">
<h3>服務(wù)器輸出:</h3>
<textarea id="responseText" style="width: 400px; height: 300px"></textarea>
<input type="button" onclick="javascript:document.getElementById('responseText').value=''" value="清空內(nèi)容">
</form>
</body>
<script type="text/javascript">
var socket;
if (window.WebSocket) {
socket = new WebSocket("ws://127.0.0.1:9999/ws")
var ta = document.getElementById("responseText");
socket.onmessage = function (event) {
ta.value = ta.value + "\n" + event.data;
}
socket.onopen = function (event) {
ta.value = "連接開(kāi)啟"
}
socket.onclose = function (event) {
ta.value = ta.value + "\n" + "連接關(guān)閉";
}
} else {
alert("瀏覽器不支持websocket")
}
function send(message) {
if(!window.WebSocket) {
return;
}
if(socket.readyState == WebSocket.OPEN){
socket.send(message)
}else{
alert("連接尚未成功")
}
}
</script>
</html>