undertow服务器分析
即将发布的JBoss Application Server版本将不再使用Tomcat作为集成的Web服务器,而是将其替换为undertow 。 undertow的体系结构基于可通过Builder API动态添加到服务器的处理程序。 这种方法类似于在Node.js中构造Web服务器的方式。 它使开发人员可以轻松地将Underwow Web服务器嵌入到其应用程序中。 由于功能是通过Builder API完成的,因此只能添加一个人的应用程序中真正需要的功能。 除此之外,undertow支持WebSockets和版本3.1中的Servlet API。 它可以作为阻塞服务器或非阻塞服务器运行,据说,首次测试已经证明Undertow是用Java编写的最快的Web服务器。
由于所有这些听起来很有希望,所以让我们尝试设置一个简单的websocket服务器。 和往常一样,我们从创建一个简单的Java项目开始,并添加undertow maven依赖项:
<dependency><groupId>io.undertow</groupId><artifactId>undertow-core</artifactId><version>1.0.0.Beta20</version>
</dependency>
使用undertow的Builder API,我们的buildAndStartServer()方法如下所示:
public void buildAndStartServer(int port, String host) {server = Undertow.builder().addListener(port, host).setHandler(getWebSocketHandler()).build();server.start();
}
我们只添加一个侦听器,该侦听器指定用于侦听传入连接的端口和主机,然后添加一个websocket处理程序。 由于websocket处理程序代码更加全面,我将其放入自己的方法中:
private PathHandler getWebSocketHandler() {return path().addPath("/websocket", websocket(new WebSocketConnectionCallback() {@Overridepublic void onConnect(WebSocketHttpExchange exchange, WebSocketChannel channel) {channel.getReceiveSetter().set(new AbstractReceiveListener() {@Overrideprotected void onFullTextMessage(WebSocketChannel channel, BufferedTextMessage message) {String data = message.getData();lastReceivedMessage = data;LOGGER.info("Received data: "+data);WebSockets.sendText(data, channel, null);}});channel.resumeReceives();}})).addPath("/", resource(new ClassPathResourceManager(WebSocketServer.class.getClassLoader(), WebSocketServer.class.getPackage())).addWelcomeFiles("index.html"));
}
让我们逐行浏览此代码段。 首先,我们添加一个新路径:/ websocket。 addPath()方法的第二个参数使我们可以指定要用于此路径的协议类型。 在我们的例子中,我们创建一个新的WebSocket。 匿名实现有一个onConnect()方法,在其中我们设置了AbstractReceiveListener的实现。 在这里,我们有一个方便的方法onFullTextMessage(),当客户端向我们发送文本消息时会调用该方法。 调用getData()将获取我们收到的实际消息。 在这个简单的示例中,我们只是将该字符串回显给客户端,以验证从客户端到服务器以及向后的往返是否有效。
为了执行一些简单的手动测试,我们还在路径/下添加了第二个资源,该资源提供一些静态HTML和JavaScript文件。 包含这些文件的目录作为ClassPathResourceManager的实例给出。 当客户端请求路径/时,addWelcomeFiles()的调用告诉undertow服务器哪个文件。
index.html看起来像这样:
</pre>
<html>
<head><title>Web Socket Test</title></head>
<body><script src="jquery-2.0.3.min.js"></script><script src="jquery.gracefulWebSocket.js"></script><script src="websocket.js"></script><form onsubmit="return false;"><input type="text" name="message" value="Hello, World!"/><input type="button" value="Send Web Socket Data" onclick="send(this.form.message.value)"/></form><div id="output"></div>
</body>
</html>
<pre>
我们JavaScript代码被换成websocket.js文件。 我们使用jquery和jquery-Plugin gracefulWebSocket来简化客户端开发:
var ws = $.gracefulWebSocket("ws://127.0.0.1:8080/websocket");
ws.onmessage = function(event) {var messageFromServer = event.data;$('#output').append('Received: '+messageFromServer+'');
}function send(message) {ws.send(message);
}
通过调用$ .gracefulWebSocket()创建WebSocket对象后,我们可以为传入消息注册回调函数。 在此方法中,我们仅将消息字符串附加到页面的DOM。 send()方法只是对gracefulWebSocket的send()方法的调用。
现在启动应用程序并在Web浏览器中打开URL http://127.0.0.1:8080/时 ,我们将看到以下页面:
输入一些字符串并单击“发送Web套接字数据”按钮,将消息发送到服务器,服务器作为响应将其回显给客户端。
既然我们知道一切都会按预期进行,那么我们想使用junit测试用例来保护我们的代码免于回归。 作为一个websocket客户,我选择了jetty-websocket库:
<dependency><groupId>org.eclipse.jetty</groupId><artifactId>jetty-websocket</artifactId><version>8.1.0.RC5</version><scope>test</scope>
</dependency>
在测试案例中,我们构建并启动websocket服务器以打开到websocket端口的新连接。 jetty-websocket的WebSocket实现允许我们为open和close事件实现两种回调方法。 在打开的回调中,我们将测试消息发送给客户端。 其余代码等待连接建立,关闭连接并断言服务器已收到消息:
@Test
public void testStartAndBuild() throws Exception {subject = new WebSocketServer();subject.buildAndStartServer(8080, "127.0.0.1");WebSocketClient client = new WebSocketClient();Future connectionFuture = client.open(new URI("ws://localhost:8080/websocket"), new WebSocket() {@Overridepublic void onOpen(Connection connection) {LOGGER.info("onOpen");try {connection.sendMessage("TestMessage");} catch (IOException e) {LOGGER.error("Failed to send message: "+e.getMessage(), e);}}@Overridepublic void onClose(int i, String s) {LOGGER.info("onClose");}});WebSocket.Connection connection = connectionFuture.get(2, TimeUnit.SECONDS);assertThat(connection, is(notNullValue()));connection.close();subject.stopServer();Thread.sleep(1000);assertThat(subject.lastReceivedMessage, is("TestMessage"));
}
- 和往常一样,您可以在github上找到源代码。
结论
Undertow的Builder API使构建Websocket服务器和满足您需求的嵌入式Web服务器变得容易。 这也简化了自动测试,因为您不需要在集成测试之前和之后启动和停止服务器的任何特定maven插件。 除此之外,jQuery插件jquery-graceful-websocket允许您仅使用几行代码就可以通过websocket发送和接收消息。
翻译自: https://www.javacodegeeks.com/2013/11/building-and-testing-a-websocket-server-with-undertow.html
undertow服务器分析