Netty.docs: User guide for 4.x https://netty.io/wiki/user-guide-for-4.x.html

The most simplistic protocol in the world is not 'Hello, World!' but DISCARD. It's a protocol that discards any received data without any response.

To implement the DISCARD protocol, the only thing you need to do is to ignore all received data. Let us start straight from the handler implementation, which handles I/O events generated by Netty.

世上最简单的协议不是'Hello, World!' 而是 DISCARD(抛弃服务)。这个协议将会抛弃任何收到的数据,而不响应。

为了实现 DISCARD 协议,你只需忽略所有收到的数据。让我们从 handler (处理器)的实现开始,handler 是由 Netty 生成用来处理 I/O 事件的。

Writing a Discard Server 写个抛弃服务器 · GitBook https://waylau.com/netty-4-user-guide/Getting%20Started/Writing%20a%20Discard%20Server.html

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>nettyG</groupId>
<artifactId>nettyA</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.30.Final</version>
</dependency>
</dependencies>
</project> D:\nettyA\src\main\java\com\test\DiscardServerHandler.java
package com.test;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter; public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
((ByteBuf) msg).release();
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

1.DiscardServerHandler 继承自 ChannelInboundHandlerAdapter,这个类实现了 ChannelInboundHandler接口,ChannelInboundHandler 提供了许多事件处理的接口方法,然后你可以覆盖这些方法。现在仅仅只需要继承 ChannelInboundHandlerAdapter 类而不是你自己去实现接口方法。

2.这里我们覆盖了 chanelRead() 事件处理方法。每当从客户端收到新的数据时,这个方法会在收到消息时被调用,这个例子中,收到的消息的类型是 ByteBuf

3.为了实现 DISCARD 协议,处理器不得不忽略所有接受到的消息。ByteBuf 是一个引用计数对象,这个对象必须显示地调用 release() 方法来释放。请记住处理器的职责是释放所有传递到处理器的引用计数对象。通常,channelRead() 方法的实现就像下面的这段代码:


@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
// Do something with msg
} finally {
ReferenceCountUtil.release(msg);
}
}

4.exceptionCaught() 事件处理方法是当出现 Throwable 对象才会被调用,即当 Netty 由于 IO 错误或者处理器在处理事件时抛出的异常时。在大部分情况下,捕获的异常应该被记录下来并且把关联的 channel 给关闭掉。然而这个方法的处理方式会在遇到不同异常的情况下有不同的实现,比如你可能想在关闭连接之前发送一个错误码的响应消息。

目前为止一切都还不错,我们已经实现了 DISCARD 服务器的一半功能,剩下的需要编写一个 main() 方法来启动服务端的 DiscardServerHandler。

  1. DiscardServerHandler extends ChannelInboundHandlerAdapter, which is an implementation of ChannelInboundHandlerChannelInboundHandler provides various event handler methods that you can override. For now, it is just enough to extend ChannelInboundHandlerAdapter rather than to implement the handler interface by yourself.
  2. We override the channelRead() event handler method here. This method is called with the received message, whenever new data is received from a client. In this example, the type of the received message is ByteBuf.
  3. To implement the DISCARD protocol, the handler has to ignore the received message. ByteBuf is a reference-counted object which has to be released explicitly via the release() method. Please keep in mind that it is the handler's responsibility to release any reference-counted object passed to the handler. Usually, channelRead() handler method is implemented like the following:
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
try {
// Do something with msg
} finally {
ReferenceCountUtil.release(msg);
}
}
  1. The exceptionCaught() event handler method is called with a Throwable when an exception was raised by Netty due to an I/O error or by a handler implementation due to the exception thrown while processing events. In most cases, the caught exception should be logged and its associated channel should be closed here, although the implementation of this method can be different depending on what you want to do to deal with an exceptional situation. For example, you might want to send a response message with an error code before closing the connection.

So far so good. We have implemented the first half of the DISCARD server. What's left now is to write the main() method which starts the server with the DiscardServerHandler.

D:\nettyA\src\main\java\com\test\DiscardServer.java
package com.test;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel; public class DiscardServer {
private int port; public DiscardServer(int port) {
this.port = port;
} public void run() throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(new DiscardServerHandler());
}
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true); ChannelFuture f = b.bind(port).sync(); //等待服务器,socket关闭。在这个例子中,这不会发生,但你可以优雅第关闭你的服务器。 f.channel().closeFuture().sync();
} finally {
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
int port;
if (args.length > 0) {
port = Integer.parseInt(args[0]);
} else {
port = 8080;
}
new DiscardServer(port).run();
}
}
https://waylau.gitbooks.io/netty-4-user-guide/Getting%20Started/Looking%20into%20the%20Received%20Data.html

Looking into the Received Data

Now that we have written our first server, we need to test if it really works. The easiest way to test it is to use the telnet command. For example, you could enter telnet localhost 8080 in the command line and type something.

However, can we say that the server is working fine? We cannot really know that because it is a discard server. You will not get any response at all. To prove it is really working, let us modify the server to print what it has received.

We already know that channelRead() method is invoked whenever data is received. Let us put some code into the channelRead()method of the DiscardServerHandler:

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
try {
while (in.isReadable()) { // (1)
System.out.print((char) in.readByte());
System.out.flush();
}
} finally {
ReferenceCountUtil.release(msg); // (2)
}
}
  1. This inefficient loop can actually be simplified to: System.out.println(in.toString(io.netty.util.CharsetUtil.US_ASCII))
  2. Alternatively, you could do in.release() here.

If you run the telnet command again, you will see the server prints what has received.

The full source code of the discard server is located in the io.netty.example.discard package of the distribution.

现在我们已经编写出我们第一个服务端,我们需要测试一下他是否真的可以运行。最简单的测试方法是用 telnet 命令。例如,你可以在命令行上输入telnet localhost 8080或者其他类型参数。

+

然而我们能说这个服务端是正常运行了吗?事实上我们也不知道,因为他是一个 discard 服务,你根本不可能得到任何的响应。为了证明他仍然是在正常工作的,让我们修改服务端的程序来打印出他到底接收到了什么。

我们已经知道 channelRead() 方法是在数据被接收的时候调用。让我们放一些代码到 DiscardServerHandler 类的 channelRead() 方法。

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
ByteBuf in = (ByteBuf) msg;
try {
while (in.isReadable()) { // (1)
System.out.print((char) in.readByte());
System.out.flush();
}
} finally {
ReferenceCountUtil.release(msg); // (2)
}
}

1.这个低效的循环事实上可以简化为:System.out.println(in.toString(io.netty.util.CharsetUtil.US_ASCII))

2.或者,你可以在这里调用 in.release()。

如果你再次运行 telnet 命令,你将会看到服务端打印出了他所接收到的消息。

package com.test;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil; public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) {
// ((ByteBuf) msg).release();
ByteBuf in = (ByteBuf) msg;
try {
while (in.isReadable()) { // (1)这个低效的循环事实上可以简化为:
//System.out.println(in.toString(CharsetUtil.US_ASCII));
System.out.print((char) in.readByte());
System.out.flush();
}
} finally {
ReferenceCountUtil.release(msg);// (2)
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}

"C:\Program Files\Java\jdk1.8.0_171\bin\java" "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2017.3.4\lib\idea_rt.jar=60542:C:\Program Files\JetBrains\IntelliJ IDEA 2017.3.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;D:\javaNettyAction\NettyA\target\classes;C:\Users\sas\.m2\repository\io\netty\netty-all\4.1.30.Final\netty-all-4.1.30.Final.jar" com.test.DiscardServer
GET / HTTP/1.1
Host: localhost:8080
Connection: keep-alive
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-TW,zh;q=0.9,en-US;q=0.8,en;q=0.7,zh-CN;q=0.6,cy;q=0.5
Cookie: Pycharm-8d0b2786=568b4aae-c829-4e47-ab4b-ddc1476c8726; Idea-80a56cc9=5ec4599e-2cf3-4fc1-b0c2-3fb43cf0485d




Writing a Discard Server 写个抛弃服务器 世上最简单的协议的更多相关文章

  1. 用C写一个web服务器(四) CGI协议

    * { margin: 0; padding: 0 } body { font: 13.34px helvetica, arial, freesans, clean, sans-serif; colo ...

  2. Writing a Discard Server

    Netty.docs: User guide for 4.x https://netty.io/wiki/user-guide-for-4.x.html

  3. Mysql 连接提示 Client does not support authentication protocol requested by server 客户端不支持服务器请求的身份验证协议;考虑升级MySQL客户端

    由于查阅了很多百度文档发现很多方法比较复杂,所以写个备忘: 首先,进入MySQL 8.0Command Line Client -Unicode,输入密码,登录进去. 然后,在命令行输入:ALTER ...

  4. 【Netty】Netty的Hello World程序之Discard Server

    一.有关Discard Server的说明 世界上最简单的协议(程序)不是“Hello, World!”而是Discard(丢弃).它是一种丢弃任何接收到的数据而没有任何响应的协议. 要实现丢弃协议, ...

  5. java写的web服务器

    经常用Tomcat,不知道的以为Tomcat很牛,其实Tomcat就是用java写的,Tomcat对jsp的支持做的很好,那么今天我们用java来写一个web服务器 //首先得到一个server, S ...

  6. 转:C#写的WEB服务器

    转:http://www.cnblogs.com/x369/articles/79245.html 这只是一个简单的用C#写的WEB服务器,只实现了get方式的对html文件的请求,有兴趣的朋友可以在 ...

  7. 徒手用Java来写个Web服务器和框架吧<第二章:Request和Response>

    徒手用Java来写个Web服务器和框架吧<第一章:NIO篇> 接上一篇,说到接受了请求,接下来就是解析请求构建Request对象,以及创建Response对象返回. 多有纰漏还请指出.省略 ...

  8. 使用node.js 文档里的方法写一个web服务器

    刚刚看了node.js文档里的一个小例子,就是用 node.js 写一个web服务器的小例子 上代码 (*^▽^*) //helloworld.js// 使用node.js写一个服务器 const h ...

  9. kotlin和vertx和mongo写的一个服务器验证登陆功能(很简陋)

    包结构长这个样子: server包:(服务器相关配置) HttpServer:用ver.x创建了一个http服务器,把接收到的req请求传入RPCRequest中: RPCRequest:解析请求bo ...

随机推荐

  1. 0062 Spring MVC的文件上传与下载--MultipartFile--ResponseEntity

    文件上传功能在网页中见的太多了,比如上传照片作为头像.上传Excel文档导入数据等 先写个上传文件的html <!DOCTYPE html> <html> <head&g ...

  2. ASP.NET基础(一)

    ExecuteNonQuery()的用法 下面我们将详细讲解如何在Page_Load()中对数据库的增加.删除.修改,最后我们再来总结一下ExecuteNonQuery(),ExecuteScalar ...

  3. 一款基于css3鼠标经过圆形旋转特效

    今天给大家分享一款基于css3鼠标经过圆形旋转特效.当鼠标经过的时候图片边框颜色旋转,图片显示详情.该实例适用浏览器:IE8.360.FireFox.Chrome.Safari.Opera.傲游.搜狗 ...

  4. mysql数据库批量操作

    批量KILL会话: 1.首先,根据条件将查询到要kill的进程写入文件:如:desc information_schema.processlist; SELECT concat('KILL ',id, ...

  5. Spring MVC之@RequestParam @RequestBody @RequestHeader 等详解<转>

    简介: handler method 参数绑定常用的注解,我们根据他们处理的Request的不同内容部分分为四类:(主要讲解常用类型) A.处理requet uri 部分(这里指uri templat ...

  6. 【转】伪O2O已死?2016年实体零售将迎来真正的O2O

    O2O果真如所谓的经济学家许小年所说“是两边都是零,中间一个2货”吗?我觉得,经济学家不是说相声的,这种哗众取宠的观点不应该出自一个严谨的经济学家之口.而且,我也不认为许小年真正懂什么叫O2O. 但O ...

  7. multimap 小例子

    场景: 按DDX值倒序取前十的板块代码,用 map<float, string, greater<float> > mapBKDDX; 存储时,相同DDX值的板块只能存储第一个 ...

  8. 在函数体的“出口处”,对 return 语句的正确性和效率进行检查

    在函数体的“出口处”,对 return 语句的正确性和效率进行检查. 如果函数有返回值,那么函数的“出口处”是 return 语句. 我们不要轻视 return 语 句.如果 return 语句写得不 ...

  9. 嵌入式开发之davinci--- ccs 编译lib库

    (1)ccs 简介 (2)ccs 输出格式coff elf (3)ccs 编译lib 算法库 (4)ccs 存在的问题 ---------------------------------------- ...

  10. 【BZOJ】1050: [HAOI2006]旅行comf(暴力+并查集)

    http://www.lydsy.com/JudgeOnline/problem.php?id=1050 表示被暴力吓到了orz 我竟然想不到...我竟然还想到分数规划,,但是不可做...然后又想到最 ...