<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    聶永的博客

    記錄工作/學(xué)習(xí)的點(diǎn)點(diǎn)滴滴。

    SO_REUSEPORT學(xué)習(xí)筆記補(bǔ)遺

    前言

    因?yàn)槟芰τ邢蓿€是有很多東西(SO_REUSEADDR和SO_REUSEPORT的區(qū)別等)沒有能夠在一篇文字中表達(dá)清楚,作為補(bǔ)遺,也方便以后自己回過頭來復(fù)習(xí)。

    SO_REUSADDR VS SO_REUSEPORT

    兩者不是一碼事,沒有可比性。有時(shí)也會(huì)被其搞暈,自己總結(jié)的不好,推薦StackOverflow的Socket options SO_REUSEADDR and SO_REUSEPORT, how do they differ?資料,總結(jié)的很全面。

    簡(jiǎn)單來說:

    • 設(shè)置了SO_REUSADDR的應(yīng)用可以避免TCP 的 TIME_WAIT 狀態(tài) 時(shí)間過長(zhǎng)無法復(fù)用端口,尤其表現(xiàn)在應(yīng)用程序關(guān)閉-重啟交替的瞬間
    • SO_REUSEPORT更強(qiáng)大,隸屬于同一個(gè)用戶(防止端口劫持)的多個(gè)進(jìn)程/線程共享一個(gè)端口,同時(shí)在內(nèi)核層面替上層應(yīng)用做數(shù)據(jù)包進(jìn)程/線程的處理均衡

    若有困惑,推薦兩者都設(shè)置,不會(huì)有沖突。

    Netty多線程使用SO_REUSEPORT

    上一篇講到SO_REUSEPORT,多個(gè)程綁定同一個(gè)端口,可以根據(jù)需要控制進(jìn)程的數(shù)量。這里講講基于Netty 4.0.25+Epoll navtie transport在單個(gè)進(jìn)程內(nèi)多個(gè)線程綁定同一個(gè)端口的情況,也是比較實(shí)用的。

    TCP服務(wù)器,同一個(gè)進(jìn)程多線程綁定同一個(gè)端口

    這是一個(gè)PING-PONG示范應(yīng)用:

         public void run() throws Exception {
                final EventLoopGroup bossGroup = new EpollEventLoopGroup();
                final EventLoopGroup workerGroup = new EpollEventLoopGroup();
                ServerBootstrap b = new ServerBootstrap();
    
               b.group(bossGroup, workerGroup)
                         .channel(EpollServerSocketChannel. class)
                         .childHandler( new ChannelInitializer<SocketChannel>() {
                                @Override
                                public void initChannel(SocketChannel ch) throws Exception {
                                    ch.pipeline().addLast(
                                                new StringDecoder(CharsetUtil.UTF_8 ),
                                                new StringEncoder(CharsetUtil.UTF_8 ),
                                                new PingPongServerHandler());
                               }
                         }).option(ChannelOption. SO_REUSEADDR, true)
                         .option(EpollChannelOption. SO_REUSEPORT, true)
                         .childOption(ChannelOption. SO_KEEPALIVE, true);
    
                int workerThreads = Runtime.getRuntime().availableProcessors();
               ChannelFuture future;
                for ( int i = 0; i < workerThreads; ++i) {
                    future = b.bind( port).await();
                     if (!future.isSuccess())
                          throw new Exception(String. format("fail to bind on port = %d.",
                                     port), future.cause());
               }
               Runtime. getRuntime().addShutdownHook (new Thread(){
                     @Override
                     public void run(){
                         workerGroup.shutdownGracefully();
                         bossGroup.shutdownGracefully();
                    }
               });
         }
    

    打成jar包,在CentOS 7下面運(yùn)行,檢查同一個(gè)端口所打開的文件句柄。

    # lsof -i:8000
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    java    3515 root   42u  IPv6  29040      0t0  TCP *:irdmi (LISTEN)
    java    3515 root   43u  IPv6  29087      0t0  TCP *:irdmi (LISTEN)
    java    3515 root   44u  IPv6  29088      0t0  TCP *:irdmi (LISTEN)
    java    3515 root   45u  IPv6  29089      0t0  TCP *:irdmi (LISTEN)
    

    同一進(jìn)程,但打開的文件句柄是不一樣的。

    UDP服務(wù)器,多個(gè)線程綁同一個(gè)端口

    /**
     * UDP諺語(yǔ)服務(wù)器,單進(jìn)程多線程綁定同一端口示范
     */
    public final class QuoteOfTheMomentServer {
    
           private static final int PORT = Integer.parseInt(System. getProperty("port" ,
                       "9000" ));
    
           public static void main(String[] args) throws Exception {
                 final EventLoopGroup group = new EpollEventLoopGroup();
    
                Bootstrap b = new Bootstrap();
                b.group(group).channel(EpollDatagramChannel. class)
                            .option(EpollChannelOption. SO_REUSEPORT, true )
                            .handler( new QuoteOfTheMomentServerHandler());
    
                 int workerThreads = Runtime.getRuntime().availableProcessors();
                 for (int i = 0; i < workerThreads; ++i) {
                      ChannelFuture future = b.bind( PORT).await();
                       if (!future.isSuccess())
                             throw new Exception(String.format ("Fail to bind on port = %d.",
                                         PORT), future.cause());
                }
    
                Runtime. getRuntime().addShutdownHook(new Thread() {
                       @Override
                       public void run() {
                            group.shutdownGracefully();
                      }
                });
          }
    }
    }
    
    @Sharable
    class QuoteOfTheMomentServerHandler extends
                SimpleChannelInboundHandler<DatagramPacket> {
    
           private static final String[] quotes = {
                       "Where there is love there is life." ,
                       "First they ignore you, then they laugh at you, then they fight you, then you win.",
                       "Be the change you want to see in the world." ,
                       "The weak can never forgive. Forgiveness is the attribute of the strong.", };
    
           private static String nextQuote() {
                 int quoteId = ThreadLocalRandom.current().nextInt( quotes .length );
                 return quotes [quoteId];
          }
    
           @Override
           public void channelRead0(ChannelHandlerContext ctx, DatagramPacket packet)
                       throws Exception {
                 if ("QOTM?" .equals(packet.content().toString(CharsetUtil. UTF_8))) {
                      ctx.write( new DatagramPacket(Unpooled.copiedBuffer( "QOTM: "
                                  + nextQuote(), CharsetUtil. UTF_8), packet.sender()));
                }
          }
    
           @Override
           public void channelReadComplete(ChannelHandlerContext ctx) {
                ctx.flush();
          }
    
           @Override
           public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
                cause.printStackTrace();
          }
    }
    

    同樣也要檢測(cè)一下端口文件句柄打開情況:

    # lsof -i:9000
    COMMAND  PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    java    3181 root   26u  IPv6  27188      0t0  UDP *:cslistener
    java    3181 root   27u  IPv6  27217      0t0  UDP *:cslistener
    java    3181 root   28u  IPv6  27218      0t0  UDP *:cslistener
    java    3181 root   29u  IPv6  27219      0t0  UDP *:cslistener
    

    小結(jié)

    以上為Netty+SO_REUSEPORT多線程綁定同一端口的一些情況,是為記載。

    posted on 2015-02-25 22:23 nieyong 閱讀(6703) 評(píng)論(1)  編輯  收藏 所屬分類: Socket

    評(píng)論

    # re: SO_REUSEPORT學(xué)習(xí)筆記補(bǔ)遺 2015-02-28 10:00 額頭上長(zhǎng)痘痘是什么原因

    樓主有句話說得不錯(cuò),很多東西不是用一句話就可以說得清楚的,只有不斷總結(jié),完善。  回復(fù)  更多評(píng)論   

    公告

    所有文章皆為原創(chuàng),若轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝~

    新浪微博,歡迎關(guān)注:

    導(dǎo)航

    <2015年2月>
    25262728293031
    1234567
    891011121314
    15161718192021
    22232425262728
    1234567

    統(tǒng)計(jì)

    常用鏈接

    留言簿(58)

    隨筆分類(130)

    隨筆檔案(151)

    個(gè)人收藏

    最新隨筆

    搜索

    最新評(píng)論

    閱讀排行榜

    評(píng)論排行榜

    主站蜘蛛池模板: 久久成人免费大片| 亚洲最大视频网站| 精品国产麻豆免费网站| 久久免费国产视频| 一区二区三区视频免费观看| 亚洲人成无码网站在线观看 | 亚洲精品无码久久久久牙蜜区| 国产亚洲一区二区手机在线观看| 国产一区二区三区在线免费观看| 久久www免费人成看片| 国内永久免费crm系统z在线| 一级毛片大全免费播放| 亚洲爆乳无码精品AAA片蜜桃| 亚洲中字慕日产2020| 亚洲神级电影国语版| 久久精品国产亚洲AV麻豆不卡| 亚洲一区精品伊人久久伊人| 免费v片视频在线观看视频| 成人免费福利电影| 男女超爽刺激视频免费播放| 免费A级毛片无码A∨中文字幕下载| GOGOGO免费观看国语| 黄 色一级 成 人网站免费| 人人爽人人爽人人片av免费| 美女被爆羞羞网站在免费观看| 亚洲sm另类一区二区三区| 亚洲熟伦熟女专区hd高清| 亚洲依依成人亚洲社区| 亚洲欧美日韩国产精品一区| 亚洲中文字幕乱码熟女在线| 亚洲熟妇av午夜无码不卡 | 99久久99久久精品免费看蜜桃 | 亚洲一区免费视频| 亚洲fuli在线观看| 美女视频黄免费亚洲| 亚洲日韩AV一区二区三区中文 | 日韩在线a视频免费播放| 国产v片免费播放| 亚洲性日韩精品国产一区二区| 国产精品亚洲综合专区片高清久久久| 国产成人精品久久亚洲|