`

使用netty框架实现websocket服务器端

阅读更多
刚学习如何使用netty,这是netty框架中的一个示例,你可以在netty的解压后文件夹路径netty-3.5.9.Final\src\main\java\org\jboss\netty\example\http\websocketx\server下找到所有的java文件
服务器端的websocket实现入口
WebSocketServer.java
package org.jboss.netty.example.http.websocketx.server;

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

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

//websocket到服务器端的链接,建议将localhost改为主机ip,各浏览器的支持情况
/**
* 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)
* <li>Firefox 11+ (RFC 6455 aka draft-ietf-hybi-thewebsocketprotocol-17)
* </ul>
*/
public class WebSocketServer {

    private final int port;//定义websocket端口

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

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

        // Set up the event pipeline factory.
        // 设置 Socket 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 + '/');
    }

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

WebSocketServerPipelineFactory.java
package org.jboss.netty.example.http.websocketx.server;

import static org.jboss.netty.channel.Channels.*;

import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;

/**
*/
public class WebSocketServerPipelineFactory implements ChannelPipelineFactory {
    public ChannelPipeline getPipeline() throws Exception {
        // Create a default pipeline implementation.
        //创建默认的管道实现pipeline
        ChannelPipeline pipeline = pipeline();
        pipeline.addLast("decoder", new HttpRequestDecoder());
        pipeline.addLast("aggregator", new HttpChunkAggregator(65536));
        pipeline.addLast("encoder", new HttpResponseEncoder());
        pipeline.addLast("handler", new WebSocketServerHandler());
        return pipeline;
    }
}

WebSocketServerHandler.java
package org.jboss.netty.example.http.websocketx.server;

import static org.jboss.netty.handler.codec.http.HttpHeaders.*;
import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.*;
import static org.jboss.netty.handler.codec.http.HttpMethod.*;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.*;
import static org.jboss.netty.handler.codec.http.HttpVersion.*;

import org.jboss.netty.buffer.ChannelBuffer;
import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpHeaders;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketFrame;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import org.jboss.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import org.jboss.netty.logging.InternalLogger;
import org.jboss.netty.logging.InternalLoggerFactory;
import org.jboss.netty.util.CharsetUtil;

/**
* Handles handshakes and messages
*/
public class WebSocketServerHandler extends SimpleChannelUpstreamHandler {
    private static final InternalLogger logger = InternalLoggerFactory.getInstance(WebSocketServerHandler.class);

    private static final String WEBSOCKET_PATH = "/websocket";

    private WebSocketServerHandshaker handshaker;

    //接收前台传来的message
    @Override
    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);
        }
    }

    private void handleHttpRequest(ChannelHandlerContext ctx, HttpRequest req) throws Exception {
        // Allow only GET methods.    只允许GET方法
        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("/")) {  //设置response
            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  socket握手
        WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(
                getWebSocketLocation(req), null, false);
        handshaker = wsFactory.newHandshaker(req);
        if (handshaker == null) {
            wsFactory.sendUnsupportedWebSocketVersionResponse(ctx.getChannel());
        } else {
            handshaker.handshake(ctx.getChannel(), req).addListener(WebSocketServerHandshaker.HANDSHAKE_LISTENER);
        }
    }

    private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) {

        // Check for closing frame    检查websocket是否关闭
        if (frame instanceof CloseWebSocketFrame) {
            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();
        if (logger.isDebugEnabled()) {
            logger.debug(String.format("Channel %s received %s", ctx.getChannel().getId(), request));
        }
        ctx.getChannel().write(new TextWebSocketFrame(request.toUpperCase()));
    }

    private static void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
        // Generate an error page if response status code is not OK (200).
        if (res.getStatus().getCode() != 200) {
            res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
            setContentLength(res, res.getContent().readableBytes());
        }

        // Send the response and close the connection if necessary.
        ChannelFuture f = ctx.getChannel().write(res);
        if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
            f.addListener(ChannelFutureListener.CLOSE);
        }
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
        e.getCause().printStackTrace();
        e.getChannel().close();
    }

    private static String getWebSocketLocation(HttpRequest req) {
        return "ws://" + req.getHeader(HttpHeaders.Names.HOST) + WEBSOCKET_PATH;
    }
}

前台页面
index.html
<html><head><title>Web Socket Client</title></head> 
<body> 
<script type="text/javascript"> 
var socket; 
if (!window.WebSocket) { 
    window.WebSocket = window.MozWebSocket; 

// Javascript Websocket Client 
if (window.WebSocket) { 
    socket = new WebSocket("ws://localhost:8080/websocket"); 
    socket.onmessage = function(event) { 
        var ta = document.getElementById('responseText'); 
        ta.value = ta.value + '\n' + event.data 
    }; 
    socket.onopen = function(event) { 
        var ta = document.getElementById('responseText'); 
        ta.value = "Web Socket opened!"; 
    }; 
    socket.onclose = function(event) { 
        var ta = document.getElementById('responseText'); 
        ta.value = ta.value + "Web Socket closed"; 
    }; 
} else { 
    alert("Your browser does not support Web Socket."); 

// Send Websocket data 
function send(message) { 
    if (!window.WebSocket) { return; } 
    if (socket.readyState == WebSocket.OPEN) { 
        socket.send(message); 
    } else { 
        alert("The socket is not open."); 
    } 

</script> 

<form onsubmit="return false;"> 
<h3>Receive :</h3>
<textarea id="responseText" style="width:500px;height:300px;"></textarea>
<br>
<h3>Send :</h3> <input type="text" name="message" value="Hello World!"/><input type="button" value="Send Web Socket Data" onclick="send(this.form.message.value)" /> 

</form> 
</body> 
</html> 

注意,前台页面建立websocket时socket = new WebSocket("ws://localhost:8080/websocket"); 中的端口必须和服务器端开启服务占用的端口相同new WebSocketServer(port).run();
要import所有的类

主要应用到的netty类的简要说明,具体使用方法请参考API
Bootstrap  一个辅助类的初始化频道。这个类提供了常见的数据结构,它的子类初始化通道和他们的孩子通道使用常用的数据结构。
ServerBootstrap  创建一个新的服务器端的通道和接受传入连接的助手类。
ChannelPipeline  ChannelHandlers处理或拦截ChannelEvents频道的列表。 ChannelPipeline实现Intercepting Filter模式,给予用户完全控制事件如何处理,以及如何在管道中的ChannelHandlers互相交流的一种高级形式。
WebSocketServerHandshakerFactory  为服务器提供的适当的握手类

netty官网:https://netty.io/
分享到:
评论
1 楼 parisspring 2013-09-27  

请问,websocketServer是怎么启动起来的,感觉一运行websocket的java应用程序后,前台的web页面就可以运行了,感觉很晕,前台的web页面应该是有web容器启动才能运行的。
另外一个问题是,服务器端的程序在项目1种,客户端index.html程序在项目2种,客户端的程序部署可以在其他的服务器上吧。我将websocketserver中的端口设置为8089就开始有报错,很奇怪

相关推荐

    基于Netty的Java WebSocket集群框架。.zip

    在WebSocket服务器端,Netty提供了WebSocketServerProtocolHandler来处理WebSocket握手和消息传输。 2. **WebSocket协议**:WebSocket协议是HTTP/1.1协议的一个扩展,通过"Upgrade"头字段进行升级,建立起一个持久...

    netty+websocket实现心跳和断线重连

    创建 WebSocket 服务器端,我们需要实现 `ServerBootstrap` 类,配置 `EventLoopGroup` 用于处理 I/O 事件,然后指定 `ServerSocketChannel` 的类型为 `NioServerSocketChannel`。接着,定义一个自定义的 `...

    基于java+Netty实现的WebSocket聊天室+支持几万人同时在线聊天无压力+源码+文档+服务端+客户端(高分优秀项目)

    服务器端使用Netty作为通信框架,支持客户端通过WebSocket通信。服务器会检测链路是否处于空闲,如果60秒内没有收到客户端的任何消息,那么服务器会主动关闭该链路。 为保证链路的可用性,服务器会定时发送Ping消息...

    netty3实现的websocket服务

    总的来说,这个项目提供了一个很好的起点,让学习者了解如何利用Netty 3构建WebSocket服务器,并通过实践来增强对Netty框架的理解。同时,它也展示了Netty如何处理网络通信和协议解析,这对于任何想深入学习网络编程...

    netty-websocket-example 基于netty的websocket实现示例

    在“netty-websocket-example”这个项目中,我们将看到如何使用 Netty 实现 WebSocket 的客户端和服务器端。首先,让我们详细了解一下 Netty 和 WebSocket 的基本概念和工作原理。 Netty 框架的核心理念是基于...

    netty实现websocket server

    在本文中,我们将深入探讨如何使用 Netty 实现 WebSocket 服务器,以及与 Java 客户端进行交互的过程。 WebSocket 协议是一种在浏览器和服务器之间建立长连接的协议,它允许双向通信,即服务器可以主动向客户端推送...

    netty+websocket聊天室例子(可私聊)

    Netty和WebSocket的结合,使得我们可以轻松地构建出实时、高效的聊天室应用,其中私聊功能的实现主要依赖于服务器端的消息路由和客户端的用户界面交互。通过理解这两个技术的工作原理和Netty提供的工具,开发者可以...

    基于netty的websocket开发小结

    这篇基于Netty的WebSocket开发小结将探讨如何使用Netty实现WebSocket服务端和客户端的交互。 首先,我们要理解WebSocket的基本概念。WebSocket协议定义了一种在单个TCP连接上进行全双工通信的协议。它通过在握手...

    Spring Boot 整合 Netty + WebSocket 实时消息推送

    6. **前端实现**:在Web端,我们可以使用JavaScript的WebSocket API来建立连接,并使用Stomp库来操作STOMP协议。此外,为了支持多客户端间的通信,前端需要维护一个用户列表,并监听其他客户端发送的消息。 7. **...

    websocket+tomcat+jetty+netty

    在这个例子中,可能包含了实现WebSocket服务器端逻辑的Servlet或过滤器,以及相关的配置文件。 总结来说,"websocket+tomcat+jetty+netty"这个主题涵盖了WebSocket协议及其在不同服务器框架中的实现。Tomcat、Jetty...

    netty+websocket通讯例子

    在 Netty 中实现 WebSocket 服务器端: 1. 创建 `WebSocketServerBootstrap` 并配置 `ServerSocketChannel`。 2. 设置 `ChannelInitializer`,在新建的 Channel 上添加处理 WebSocket 连接的处理器。 3. 添加 `...

    用Netty实现Websocket(包含服务器代码和客户端网页)

    本教程将详细讲解如何使用Netty实现Websocket服务器以及对应的客户端网页。首先,我们需要理解Netty的核心概念:Channel、EventLoopGroup和Bootstrap。Channel是网络连接的抽象,用于读写数据;EventLoopGroup是一组...

    WebSocket利用netty连接入门项目

    在这个入门项目中,我们将使用Netty来实现WebSocket服务器。 1. **WebSocket协议概述** WebSocket协议基于HTTP,但与HTTP不同,它在建立连接后不再依赖HTTP头部信息,而是通过握手过程创建一个持久的连接。一旦...

    Netty版WebSocket聊天

    在实现WebSocket聊天应用时,首先需要在服务器端创建一个WebSocket服务端处理器,这个处理器会监听WebSocket连接的建立、关闭以及接收到的数据。接着,服务器需要解析接收到的消息并根据需求进行处理,例如将消息...

    基于Netty5.0的高级案例NettyWebsocket

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

    简易版netty websocket通讯demo 聊天

    通过这个简易版的 Netty WebSocket 聊天 demo,开发者可以学习如何在服务器端和客户端使用 Netty 实现 WebSocket 连接,理解协议处理和消息传递的基本流程,为进一步开发更复杂的应用奠定基础。

    Netty、WebSocket、Spring代码案例研究 即时通讯

    2. **Spring WebSocket**:Spring提供WebSocket支持,包括消息发布/订阅模型(Stomp),简化了WebSocket服务器端的开发。 3. **Spring MVC**:结合WebSocket,Spring MVC可以处理HTTP请求,并与WebSocket客户端交互...

    Netty实现websocket

    虽然题目主要涉及服务器端实现,但 Netty 也支持 WebSocket 客户端。你可以使用 `WebSocketClientBootstrap` 来创建 WebSocket 客户端,配置连接参数,并添加相应的处理器。 11. **部署与测试** 题目中的 `...

    springboot基础netty和websocket

    同时,需要在Netty端实现WebSocket的协议处理,包括握手、数据帧解析和编码等。 为了封装Netty的相关接口,我们可以创建一个NettyServer类,负责启动和停止服务器,以及处理WebSocket连接的生命周期。这个类应该...

    Netty整合webSocket

    Netty 是一个高性能、异步事件驱动的网络应用程序框架,常用于开发高效的服务器和客户端应用。WebSocket 是一种在客户端和服务器之间建立长连接的协议,它允许双向通信,即服务器和客户端都可以主动发送数据。在Java...

Global site tag (gtag.js) - Google Analytics