`

基于netty的websocket开发小结

阅读更多
WebSocket是html5规范新引入的功能,用于解决浏览器与后台服务器双向通讯的问题,使用WebSocket技术,后台可以随时向前端推送消息,以保证前后台状态统一,在传统的无状态HTTP协议中,这是“无法做到”的。

WebSocket提出之前,为了解决后台推送消息到前台的需求,提出了一些解决方案,这些方案使用已有的技术(如ajax,iframe,flashplayer,java applet ...),通过一些变通的处理来实现。

webSocket是html5新引入的技术,允许后台随时向前端发送文本或者二进制消息,WebSocket是一种全新的协议,不属于http无状态协议,协议名为"ws",这意味着一个websocket连接地址会是这样的写法:
ws://127.0.0.1:8080/websocket。ws不是http,所以传统的web服务器不一定支持,需要服务器与浏览器同时支持, WebSocket才能正常运行,目前的支持还不普遍,需要特别的web服务器和现代的浏览器。

浏览器对WebSocket的支持
Google Chrome浏览器最先支持WebSocket,随后是Safari,Firefox,此外最新版本的Opera和IE(Opera11,IE10)也支持WebSocket。

客户端WebSocket的主要方法

1 构造函数
 var websocket = new WebSocket("ws://127.0.0.1:8080/websocket");

2 事件open/message/close/error
WebSocket#onopen, onmessage, onclose, onerror
连接打开时,回调onopen方法,接收到后台消息时会触发到onmessage事件,后台关闭时调用onclose,出现连接异常时可在onerror中捕获
发送消息 - WebSocket#send(data)
关闭连接 - WebSocket#close(optional code, optional reason)

下面是一个简单的html5连接websocket服务器测试页
<!DOCTYPE html>
<html>
<head>

<script type="text/javascript" charset="utf-8" >
  window.WebSocket = window.WebSocket || window.MozWebSocket;
  
 if (!window.WebSocket){
     alert("WebSocket not supported by this browser");
     return;
 };
  
var websocket = new WebSocket("ws://127.0.0.1:8080/websocket");
 websocket.onmessage = function(evt){
     var data = evt.data;
      alert("received message: " + data);
 }

 function send() {
 var name = document.querySelector("input[name=name]").value;
    alert("websocket send message:"+name);
    websocket.send(name);
 }
</script>
</head>
<body>
<label for="name">What’s your name:</label>
<input type="text" id="name" name="name" />
<button onclick="send()">Send</button>
<div id="message" style="color:red"></div>
</body>
</html>


服务器对WebSocket的支持
    WebSocket不同于http协议,传统的web服务器通常不支持WebSocket.而websocket服务器端的开发大概有借助Socket.IO开发、NodeJS和Socket.IO联合开发以及借助netty框架开发等等。这里只对netty框架下的websocket开发进行一个简单的说明!

    websocket的协议比较简单, 客户端和普通的浏览器一样通过80或者443端口和服务器进行请求握手,服务器根据http header识别是否一个websocket请求,如果是,则将请求升级为一个websocket连接,握手成功后就进入双向长连接的数据传输阶段. websocket的数据传输是基于帧的方式: 0x00 表示数据开始, 0xff表示数据结束,数据以utf-8编码.

    简单的说,第一次请求客户端发送的是http请求,请求头中包含websocket相关的信息,服务器端对请求进行验证:

   private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
        // Allow only GET methods.
        if (req.getMethod() != GET) {
            sendHttpResponse(ctx, req, new DefaultHttpResponse(HTTP_1_1, FORBIDDEN));
            return;
        }

        // Send the demo page and favicon.ico
        if (req.getUri().equals("/")) {
            HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK);

            ChannelBuffer content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req));

            res.setHeader(CONTENT_TYPE, "text/html; charset=UTF-8");
            setContentLength(res, content.readableBytes());

            res.setContent(content);
            sendHttpResponse(ctx, req, res);
            return;
        } else if (req.getUri().equals("/favicon.ico")) {
            HttpResponse res = new DefaultHttpResponse(HTTP_1_1, NOT_FOUND);
            sendHttpResponse(ctx, req, res);
            return;
        }

        // Handshake
        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                this.getWebSocketLocation(req), null, false);
        this.handshaker = wsFactory.newHandshaker(req);
        if (this.handshaker == null) {
            wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
        } else {
            this.handshaker.handshake(ctx.getChannel(), req);
            System.out.println(WebSocketServer.recipients.size());
            WebSocketServer.recipients.add(ctx.getChannel());
            System.out.println(WebSocketServer.recipients.size());
            System.out.println(ctx.getChannel().getId());
        }
    }


验证成功后,将请求升级为一个websocket连接,之后的通信就进入双向长连接的数据传输阶段。

    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {

        // Check for closing frame
        if (frame instanceof CloseWebSocketFrame) {
            this.handshaker.close(ctx.getChannel(), (CloseWebSocketFrame) frame);
            return;
        } else if (frame instanceof PingWebSocketFrame) {
            ctx.getChannel().write(new PongWebSocketFrame(frame.getBinaryData()));
            return;
        } else if (!(frame instanceof TextWebSocketFrame)) {
            throw new UnsupportedOperationException(String.format("%s frame types not supported", frame.getClass()
                    .getName()));
        }

        // Send the uppercase string back.
        String request = ((TextWebSocketFrame) frame).getText();
        logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));

//        WebSocketServer.recipients.write(new TextWebSocketFrame(request.toUpperCase()));
        ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));
    }


一定要注意在messageReceived中要对HttpRequest和WebSocketFrame分别进行处理。
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
        Object msg = e.getMessage();
        if (msg instanceof HttpRequest) {
            handleHttpRequest(ctx, (HttpRequest) msg);
        } else if (msg instanceof WebSocketFrame) {
            handleWebSocketFrame(ctx, (WebSocketFrame) msg);
        }
    }


服务入口
package com.etao.mobile.websocket;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.group.ChannelGroup;
import org.jboss.netty.channel.group.DefaultChannelGroup;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;

/**
 * A HTTP server which serves Web Socket requests at:
 * 
 * http://localhost:8080/websocket
 * 
 * Open your browser at http://localhost:8080/, then the demo page will be
 * loaded and a Web Socket connection will be made automatically.
 * 
 * This server illustrates support for the different web socket specification
 * versions and will work with:
 * 
 * <ul>
 * <li>Safari 5+ (draft-ietf-hybi-thewebsocketprotocol-00)
 * <li>Chrome 6-13 (draft-ietf-hybi-thewebsocketprotocol-00)
 * <li>Chrome 14+ (draft-ietf-hybi-thewebsocketprotocol-10)
 * <li>Chrome 16+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
 * <li>Firefox 7+ (draft-ietf-hybi-thewebsocketprotocol-10)
 * </ul>
 */
public class WebSocketServer {

	private final int port;

	public static ChannelGroup recipients = new DefaultChannelGroup();

	public WebSocketServer(int port) {
		this.port = port;
	}

	public void run() {
		// Configure the server.
		ServerBootstrap bootstrap = new ServerBootstrap(
				new NioServerSocketChannelFactory(Executors
						.newCachedThreadPool(), Executors.newCachedThreadPool()));

		// Set up the event pipeline factory.
		bootstrap.setPipelineFactory(new WebSocketServerPipelineFactory());

		// Bind and start to accept incoming connections.
		bootstrap.bind(new InetSocketAddress(port));

		System.out.println("Web socket server started at port " + port + '.');
		System.out
				.println("Open your browser and navigate to http://localhost:"
						+ port + '/');
	}

	public static void main(String[] args) {
		int port;
		if (args.length > 0) {
			port = Integer.parseInt(args[0]);
		} else {
			port = 8080;
		}
		new WebSocketServer(port).run();
	}
}


一定要注意的是netty3.0一下的版本是不支持websocket的!我这里用的是3.3.0.Final版本。

可能存在的隐患:不同草案的websocket 握手标准有所不同,因此netty在这方面的检测是否可以满足要求?

我这里也参考了 基于Websocket草案10协议的升级及基于Netty的握手实现,在此对冯立彬的博客表示感谢!
分享到:
评论
5 楼 niuka 2015-08-11  
非常好,最近我一直苦于java怎么跟浏览器建立长连接,看了你的分享之后,果然搞定了,谢谢。。。  
4 楼 zhaotong2012 2014-06-25  
我想问一下 这个我想通过url地址 获取服务器端数据 时时获取 这个可以实现么
3 楼 cpjsjxy 2014-06-11  
beyond667 写道
文章不错,也能正常跑。
有个问题,这个demo里是给localhost里发消息的,怎么样像QQ那样点到点发消息呢?


客户端通过服务器端做消息中转就好啦,实现起来并不复杂!
2 楼 beyond667 2014-05-28  
文章不错,也能正常跑。
有个问题,这个demo里是给localhost里发消息的,怎么样像QQ那样点到点发消息呢?
1 楼 syd6815892 2014-02-11  
少了JAR包啊

相关推荐

    基于Netty5.0的高级案例NettyWebsocket

    "基于Netty5.0的高级案例NettyWebsocket" 这个标题揭示了我们将会探讨一个使用Netty 5.0框架实现的WebSocket服务器的高级应用场景。Netty是一个高性能、异步事件驱动的网络应用程序框架,主要用于快速开发可维护的高...

    Spring+Netty+WebSocket实例

    在现代Web开发中,实时通信已经成为一个不可或缺的功能,Spring、Netty和WebSocket的结合为构建高性能、低延迟的实时应用提供了强大的解决方案。本实例将详细探讨如何利用这三种技术进行集成,实现高效的双向通信。 ...

    netty websocket

    Netty Websocket是一个基于Java的高性能网络应用框架,专门用于构建高效的、可扩展的网络服务器和客户端。在本文中,我们将深入探讨Netty与WebSocket的结合使用,以及它们在实际开发中的重要性。 WebSocket是一种在...

    websocket+tomcat+jetty+netty

    总结来说,"websocket+tomcat+jetty+netty"这个主题涵盖了WebSocket协议及其在不同服务器框架中的实现。Tomcat、Jetty和Netty都是支持WebSocket的Java服务器平台,各有其优势和适用场景。理解这些技术可以帮助开发者...

    netty+websocket

    在本文中,我们将深入探讨如何利用 Netty 实现基于 WebSocket 的通信服务。 WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它为 Web 应用程序提供低延迟、双向通信的能力。WebSocket API 设计为与 HTTP ...

    聊天室 Chat Room V1.0 (SpringBoot + Netty + H5 + WebSocket + 原生JS)

    Chat Room V1.0 是一个基于SpringBoot、Netty、HTML5、WebSocket和原生JavaScript构建的多人在线聊天系统。这个项目旨在实现高效、稳定且易于维护的实时通信功能,让多个用户能够实时交流,同时提供了在线人数统计、...

    springboot-netty-websocket

    标题“springboot-netty-websocket”表明我们正在讨论一个基于Spring Boot和Netty实现WebSocket通信的项目或教程。WebSocket是一种在客户端和服务器之间建立长连接的协议,它提供了双向通信能力,即服务器和客户端都...

    springboot实现websocket发送和接收消息

    Spring Boot,作为一个流行的Java开发框架,通过其丰富的生态,支持WebSocket的集成和使用。本篇文章将深入探讨如何使用Spring Boot来实现WebSocket的发送和接收消息功能。 首先,我们需要在Spring Boot项目中添加...

    消息推送中台websocket部分 + netty 手写 RPC

    总结来说,这个项目涵盖了从WebSocket的实时通信实现到Netty手写RPC的底层细节,再到Dubbo的服务治理,涉及了现代互联网应用开发的多个重要技术领域。通过实践这样的项目,开发者不仅可以掌握消息推送系统的运作原理...

    spring-boot-websocket-netty-server代码整合

    总结起来,`Spring Boot`、`WebSocket`和`Netty`的整合,能够让我们构建一个既易于管理又具备高性能的实时Web服务。通过`Spring Boot`的自动化配置和依赖管理,我们可以快速搭建项目框架;利用`WebSocket`的双向通信...

    前台用html5 websocket 后台用netty实现聊天系统.zip

    WebSocket 提供了浏览器与服务器之间全双工、低延迟的通信方式,而 Netty 是一个高性能、异步事件驱动的网络应用程序框架,常被用于后端服务器的开发。 WebSocket 是 HTML5 的一部分,它允许在客户端和服务器之间...

    基于springboot + netty + vue的bililbili弹幕群聊系统.zip

    该项目是一个实现类似哔哩哔哩...总结,这个项目展示了如何整合多种技术来构建一个实时的、高并发的在线聊天系统,涉及到了前后端分离、实时通信、数据库设计、安全性等多个方面,是学习和实践现代Web开发的优秀案例。

    netty socketio全部包jar

    总结来说,这个压缩包提供了一整套用于构建基于Netty和Socket.IO的Web实时通信应用的库。通过这些库,开发者可以利用Java实现高效、可靠的服务器端代码,处理来自客户端的实时数据流,并进行复杂的网络通信任务。...

    netty socketio 在线聊天程序

    Netty是由JBOSS提供的一个高性能、异步事件驱动的网络应用框架,用于快速开发可维护的高性能协议服务器和客户端。它主要特点包括: 1. **异步IO模型**:Netty基于NIO(非阻塞I/O)模型,提供了一种高效的事件驱动的...

    netty in action 中文版 高清带目录 来个最便宜的

    总结来说,Netty是一个全面的、异步的事件驱动网络应用框架,它基于Java NIO,提供了易于使用、高性能、高度可扩展和可靠的网络编程解决方案。无论是对Java网络编程的新手还是有经验的开发者,Netty都提供了一个值得...

    netty与tomcat功能比较

    Netty与Tomcat虽然都服务于Java后端开发领域,但它们的侧重点有所不同。Tomcat专注于Web应用,而Netty则更加灵活多变,适用于更多场景。Netty之所以能够受到如此高的评价,与其优秀的并发性能、高效的数据传输机制...

    Netty5学习指南

    Netty 的架构基于事件驱动模型,由事件处理器链(ChannelPipeline)组成。每个处理器(ChannelHandler)负责处理特定类型的事件,如数据接收、连接建立或关闭等。这种分发机制使得代码更易于理解和维护。例如,在...

    netty源码深入分析

    Netty是基于Java NIO的一个高性能的网络通信框架,它可以用于快速开发可维护的高性能协议服务器与客户端。Netty提供了事件驱动、非阻塞的API来简化网络编程,并且内置了大量的协议支持(如HTTP、FTP、SMTP、...

    Netty_In_Action中文版

    - **定义与特点**:Netty是一个基于NIO(Non-blocking IO)技术的客户端-服务器框架,旨在简化网络应用的开发过程,尤其适合于开发高性能的服务器端应用程序。Netty提供了简单而强大的API,使得开发人员能够更加专注...

Global site tag (gtag.js) - Google Analytics