1. 程式人生 > >Netty初識之DiscardServer

Netty初識之DiscardServer

Netty

Netty專案是為了快速開發可維護的高效能高可擴充套件性協議伺服器和客戶端而努力提供非同步事件驅動的網路應用程式框架和工具。換句話說,Netty是一個NIO客戶端伺服器框架,可以快速輕鬆地開發諸如協議伺服器和客戶端之類的網路應用程式。它大大簡化了網路程式設計流程,如TCP和UDP套接字伺服器開發。

Tomcat和Netty的比較

Netty和Tomcat最大的區別就在於通訊協議,Tomcat是基於Http協議的,他的實質是一個基於http協議的web容器,但是Netty不一樣,他能通過程式設計自定義各種協議,因為netty能夠通過codec自己來編碼/解碼位元組流,完成類似redis訪問的功能,這就是netty和tomcat最大的不同

 

Netty特點:

  1. 併發高
  2. 傳輸快
  3. 封裝好

 

 

<?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>com.sengen</groupId>
  <artifactId>nettydemos</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>nettydemos</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>io.netty</groupId>
      <artifactId>netty-all</artifactId>
      <version>4.0.32.Final</version>
    </dependency>
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.7.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.20.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
package com.sengen.netty_beginner;

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;
/**
 * Created by Administrator on 2018/8/17.
 * 描述:DiscardServer 啟動類
 * @author Young
 * @create 2018-08-17 14:35
 */
public class DiscardServer {
    private int port;

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

    public static void main(String[] args) {
        int port;
        if(args.length>0){
            port = Integer.valueOf(args[1]);
        }else {
            port = 8080;
        }
        System.out.println("準備啟動中.........");
        new DiscardServer(port).run();
        //好像永遠都執行不到回家的程式碼......
        System.out.println("跑完了....肥噶!");
    }

    private void run() {
        /**NioEventLoopGroup是一個處理I/O操作的多執行緒事件迴圈.Netty為不同型別的傳輸提供了各種EventLoopGroup實現.在這個例子中,我們正在實現一個
         * 伺服器端應用程式,因此將使用兩個NioEventLoopGroup.
         * 第一個 通常稱為老闆,接收傳入的連線;
         * 第二個 通常稱為工人,一旦老闆接收連線並將接受的連線註冊給工作人員,就處理接收的連線的流量.
         *        使用多少執行緒以及他們如何對映到建立的通道取決於EventLoopGroup實現,甚至可以通過建構函式進行配置.
         */
        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workerGroup = new NioEventLoopGroup();
        try{
            /**
             * ServerBootstrap是一個幫助類,用於設定伺服器.可以直接使用Channel設定伺服器.但是一般情況都不這樣做..
             **/
            ServerBootstrap sb = new ServerBootstrap();
            sb.group(bossGroup,workerGroup)
                    /**
                     * 在這裡,我們指定使用NioServerSocketChannel類來例項化一個新的Channel來接收傳入的連線.
                     * (每個客戶端連線服務端,我們都為他們建立一個channel,那麼這個channel對於面向物件的我們來說就是一個類,我們統一對於我們接收
                     * 到的連線都初始化為:NioServerSocketChannel)
                     */
                    .channel(NioServerSocketChannel.class)
                    /**
                     * 這裡指定的處理程式將始終由新接收的Channel進行評估.ChannelInitializer是一個特殊的處理程式,旨在幫助使用者配置新的Channel.
                     * 若想通過新增一些處理程式(如DiscardServerHandler)來配置新Channel的ChannelPipeline來實現網路應用程式.
                     * 隨著應用程式的複雜化,可能在管道中新增更多的處理程式..(其實這就是需要自己重新實現包含自己處理邏輯的Channel.
                     * 類似於DiscardServerHandler,繼承ChannelInboundHandlerAdapter一樣)
                     * */
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel socketChannel) throws Exception {
                            socketChannel.pipeline().addLast(new DiscardServerHandler());
                        }
                    })
                    /**
                     * 設定特定於Channel實現的引數.正在編寫一個TCP/IP伺服器.因此可以設定套接字選項.如tcpNoDelay和keepAlive
                     *
                     * option()和childOption()方法.
                     * option()用於接收傳入連線的NioServerChannel.
                     * childOption()用於在這種情況下由父級ServerChannel接收的通道,即NioServerSocketChannel.
                     * 個人認為:前者用於配置父級Channel,後者配置自定義的子集Channel.
                    */
                    .option(ChannelOption.SO_BACKLOG,128)
                    .childOption(ChannelOption.SO_KEEPALIVE,true);

            ChannelFuture future = sb.bind(port).sync();
            future.channel().closeFuture().sync();

        }catch(Exception e){
            System.out.println("有異常,快跑...........");
        }finally{
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
        }
    }


}
package com.sengen.netty_beginner;

import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.ReferenceCountUtil;

import java.net.SocketAddress;

/**
 * Created by Administrator on 2018/8/17.
 * 描述:手動完成比hello world還簡單的程式
 * @author Young
 * @create 2018-08-17 14:29
 */
public class DiscardServerHandler extends ChannelInboundHandlerAdapter {
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        //將Object強轉成ByteBuf(引用計數物件)
//        ((ByteBuf)msg).release();
        ByteBuf in = (ByteBuf) msg;
        try {
            while (in.isReadable()) {
                Channel channel = ctx.channel();
                SocketAddress socketAddress = channel.remoteAddress();
                System.out.println(socketAddress+"連線了你");
                System.out.print((char) in.readByte());
                System.out.flush();
            }
        } finally {
            ReferenceCountUtil.release(msg);
        }

    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
//        cause.printStackTrace();
        System.out.println(ctx.channel().remoteAddress()+"強迫關閉了連線");
        System.out.println("跑完了......肥噶!");
        ctx.close();
    }
}

控制檯啟動main方法...網頁和cmd都可以訪問.....localhost:8080.....localhost改成ip通用的...

 

我感覺我要把我的github用起來了...貼程式碼不方便了.