天天看点

继续!面试继续!Netty dubbo的通信方式

小小又去面试了,小小的生活继续,(^o^)/ 这次小小的技术方面有Netty,以及Dubbo的通信方式,对这两个点进行继续的复习和学习。

1. Netty

Netty 通过缓冲区实现。

WebSocket

为什么需要WebSocket

聊天室之前采用的是轮询,效率相当的慢,所以这里采用WebSocket,实现长连接通信。WebSocket于是这样的诞生。

介绍

特点如下

  1. 建立在TCP连接之上。
  2. 与HTTP有较好的兼容性。
  3. 数据格式轻量,性能开销小,消耗小。
  4. 可以发送文本,可以发送二进制数据。
  5. 没有同源限制,可以进行任意的通信。
  6. 协议的标识符是ws。网址如下 ws://example.com:80/some/path

示例

  1. var ws = new WebSocket("wss://echo.websocket.org");
  2. ws.onopen = function(evt) {
  3. console.log("Connection open ...");
  4. ws.send("Hello WebSockets!");
  5. };
  6. ws.onmessage = function(evt) {
  7. console.log( "Received Message: " + evt.data);
  8. ws.close();
  9. ws.onclose = function(evt) {
  10. console.log("Connection closed.");

客户端的 API

新建实例

  1. var ws = new WebSocket('ws://localhost:8080');
  1. readyState属性返回实例对象的当前状态,共有四种。
  2. CONNECTING:值为0,表示正在连接。
  3. OPEN:值为1,表示连接成功,可以通信了。
  4. CLOSING:值为2,表示连接正在关闭。
  5. CLOSED:值为3,表示连接已经关闭,或者打开连接失败。

下面是一个实例

  1. switch (ws.readyState) {
  2. case WebSocket.CONNECTING:
  3. // do something
  4. break;
  5. case WebSocket.OPEN:
  6. case WebSocket.CLOSING:
  7. case WebSocket.CLOSED:
  8. default:
  9. // this never happens
  10. }
  1. webSocket.onopen
  2. 实例对象的onopen属性,用于指定连接成功后的回调函数。
  3. ws.onopen = function () {
  4. ws.send('Hello Server!');
  5. 如果要指定多个回调函数,可以使用addEventListener方法。
  6. ws.addEventListener('open', function (event) {
  7. });
  1. webSocket.onclose
  2. 实例对象的onclose属性,用于指定连接关闭后的回调函数。
  3. ws.onclose = function(event) {
  4. var code = event.code;
  5. var reason = event.reason;
  6. var wasClean = event.wasClean;
  7. // handle close event
  8. ws.addEventListener("close", function(event) {
  1. webSocket.onmessage
  2. 实例对象的onmessage属性,用于指定收到服务器数据后的回调函数。
  3. ws.onmessage = function(event) {
  4. var data = event.data;
  5. // 处理数据
  6. ws.addEventListener("message", function(event) {
  7. 注意,服务器数据可能是文本,也可能是二进制数据(blob对象或Arraybuffer对象)。
  8. ws.onmessage = function(event){
  9. if(typeof event.data === String) {
  10. console.log("Received data string");
  11. if(event.data instanceof ArrayBuffer){
  12. var buffer = event.data;
  13. console.log("Received arraybuffer");
  14. 除了动态判断收到的数据类型,也可以使用binaryType属性,显式指定收到的二进制数据类型。
  15. // 收到的是 blob 数据
  16. ws.binaryType = "blob";
  17. ws.onmessage = function(e) {
  18. console.log(e.data.size);
  19. // 收到的是 ArrayBuffer 数据
  20. ws.binaryType = "arraybuffer";
  21. console.log(e.data.byteLength);
  22. 4.6 webSocket.send()
  23. 实例对象的send()方法用于向服务器发送数据。
  24. 发送文本的例子。
  25. ws.send('your message');
  26. 发送 Blob 对象的例子。
  27. var file = document
  28. .querySelector('input[type="file"]')
  29. .files[0];
  30. ws.send(file);
  31. 发送 ArrayBuffer 对象的例子。
  32. // Sending canvas ImageData as ArrayBuffer
  33. var img = canvas_context.getImageData(0, 0, 400, 320);
  34. var binary = new Uint8Array(img.data.length);
  35. for (var i = 0; i < img.data.length; i++) {
  36. binary[i] = img.data[i];
  37. ws.send(binary.buffer);
  1. webSocket.bufferedAmount
  2. 实例对象的bufferedAmount属性,表示还有多少字节的二进制数据没有发送出去。它可以用来判断发送是否结束。
  3. var data = new ArrayBuffer(10000000);
  4. socket.send(data);
  5. if (socket.bufferedAmount === 0) {
  6. // 发送完毕
  7. } else {
  8. // 发送还没结束
  1. webSocket.onerror
  2. 实例对象的onerror属性,用于指定报错时的回调函数。
  3. socket.onerror = function(event) {
  4. // handle error event
  5. socket.addEventListener("error", function(event) {

Netty的使用

新建工程,通过meaven导入Netty的库包

  1. <dependency>
  2. <groupId>io.netty</groupId>
  3. <artifactId>netty-all</artifactId>
  4. <version>5.0.0.Alpha2</version>
  5. </dependency>

创建NettyServer

  1. package com.jiutianbian.NettyTest;
  2. import io.netty.bootstrap.ServerBootstrap;
  3. import io.netty.channel.ChannelFuture;
  4. import io.netty.channel.ChannelInitializer;
  5. import io.netty.channel.ChannelOption;
  6. import io.netty.channel.ChannelPipeline;
  7. import io.netty.channel.EventLoopGroup;
  8. import io.netty.channel.nio.NioEventLoopGroup;
  9. import io.netty.channel.socket.SocketChannel;
  10. import io.netty.channel.socket.nio.NioServerSocketChannel;
  11. public class NettyServer {
  12. private int port;
  13. public NettyServer(int port) {
  14. this.port = port;
  15. bind();
  16. private void bind() {
  17. EventLoopGroup boss = new NioEventLoopGroup();
  18. EventLoopGroup worker = new NioEventLoopGroup();
  19. try {
  20. ServerBootstrap bootstrap = new ServerBootstrap();
  21. bootstrap.group(boss, worker);
  22. bootstrap.channel(NioServerSocketChannel.class);
  23. bootstrap.option(ChannelOption.SO_BACKLOG, 1024); // 连接数
  24. bootstrap.option(ChannelOption.TCP_NODELAY, true); // 不延迟,消息立即发送
  25. bootstrap.childOption(ChannelOption.SO_KEEPALIVE, true); // 长连接
  26. bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
  27. @Override
  28. protected void initChannel(SocketChannel socketChannel)
  29. throws Exception {
  30. ChannelPipeline p = socketChannel.pipeline();
  31. p.addLast(new NettyServerHandler());// 添加NettyServerHandler,用来处理Server端接收和处理消息的逻辑
  32. ChannelFuture channelFuture = bootstrap.bind(port).sync();
  33. if (channelFuture.isSuccess()) {
  34. System.err.println("启动Netty服务成功,端口号:" + this.port);
  35. // 关闭连接
  36. channelFuture.channel().closeFuture().sync();
  37. } catch (Exception e) {
  38. System.err.println("启动Netty服务异常,异常信息:" + e.getMessage());
  39. e.printStackTrace();
  40. } finally {
  41. boss.shutdownGracefully();
  42. worker.shutdownGracefully();
  43. public static void main(String[] args) throws InterruptedException {
  44. new NettyServer(10086);

创建NettyServerHandler,用来接收和回复Client端的消息

  1. import io.netty.buffer.ByteBuf;
  2. import io.netty.buffer.Unpooled;
  3. import io.netty.channel.ChannelHandlerAdapter;
  4. import io.netty.channel.ChannelHandlerContext;
  5. import java.io.UnsupportedEncodingException;
  6. public class NettyServerHandler extends ChannelHandlerAdapter {
  7. public void channelRead(ChannelHandlerContext ctx, Object msg) {
  8. ByteBuf buf = (ByteBuf) msg;
  9. String recieved = getMessage(buf);
  10. System.err.println("服务器接收到客户端消息:" + recieved);
  11. ctx.writeAndFlush(getSendByteBuf("你好,客户端"));
  12. System.err.println("服务器回复消息:你好,客户端");
  13. } catch (UnsupportedEncodingException e) {
  14. /*
  15. * 从ByteBuf中获取信息 使用UTF-8编码返回
  16. */
  17. private String getMessage(ByteBuf buf) {
  18. byte[] con = new byte[buf.readableBytes()];
  19. buf.readBytes(con);
  20. return new String(con, "UTF8");
  21. return null;
  22. private ByteBuf getSendByteBuf(String message)
  23. throws UnsupportedEncodingException {
  24. byte[] req = message.getBytes("UTF-8");
  25. ByteBuf pingMessage = Unpooled.buffer();
  26. pingMessage.writeBytes(req);
  27. return pingMessage;

启动Server端

继续!面试继续!Netty dubbo的通信方式
  1. Netty Client端
  2. 1. 新建工程,通过meaven导入Netty的库包
  3. 导入代码同上面的Server端代码
  4. 2. 创建NettyClient
  5. 新建NettyClient类
  6. package com.jiutianbian.NettyClinetTest;
  7. import io.netty.bootstrap.Bootstrap;
  8. import io.netty.channel.socket.nio.NioSocketChannel;
  9. public class NettyClient {
  10. * 服务器端口号
  11. * 服务器IP
  12. private String host;
  13. public NettyClient(int port, String host) throws InterruptedException {
  14. this.host = host;
  15. start();
  16. private void start() throws InterruptedException {
  17. EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
  18. Bootstrap bootstrap = new Bootstrap();
  19. bootstrap.channel(NioSocketChannel.class);
  20. bootstrap.option(ChannelOption.SO_KEEPALIVE, true);
  21. bootstrap.group(eventLoopGroup);
  22. bootstrap.remoteAddress(host, port);
  23. bootstrap.handler(new ChannelInitializer<SocketChannel>() {
  24. socketChannel.pipeline().addLast(new NettyClientHandler());
  25. ChannelFuture channelFuture = bootstrap.connect(host, port).sync();
  26. System.err.println("连接服务器成功");
  27. eventLoopGroup.shutdownGracefully();
  28. new NettyClient(10086, "localhost");
  1. public class NettyClientHandler extends ChannelHandlerAdapter {
  2. private ByteBuf firstMessage;
  3. public void channelActive(ChannelHandlerContext ctx) throws Exception {
  4. byte[] data = "你好,服务器".getBytes();
  5. firstMessage = Unpooled.buffer();
  6. firstMessage.writeBytes(data);
  7. ctx.writeAndFlush(firstMessage);
  8. System.err.println("客户端发送消息:你好,服务器");
  9. public void channelRead(ChannelHandlerContext ctx, Object msg)
  10. String rev = getMessage(buf);
  11. System.err.println("客户端收到服务器消息:" + rev);

启动Client端

继续!面试继续!Netty dubbo的通信方式

Server端日志输出,此时如下

Dubbo 通信

继续阅读