国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App詳解(一)

terasum / 986人閱讀

摘要:線程切換效率低下單機(jī)核數(shù)固定,線程爆炸之后操作系統(tǒng)頻繁進(jìn)行線程切換,應(yīng)用性能急劇下降。線程切換效率低下由于模型中線程數(shù)量大大降低,線程切換效率因此也大幅度提高。將兩個(gè)線程優(yōu)雅地關(guān)閉。創(chuàng)建管道的子處理器,用于處理。

Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目介紹:https://segmentfault.com/a/11...

Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目github鏈接:https://github.com/ShimmerPig...

本章練習(xí)完整代碼鏈接:https://github.com/ShimmerPig...

Netty學(xué)習(xí) IO編程與NIO編程 傳統(tǒng)IO編程性能分析

IO編程模型在客戶(hù)端較少的情況下運(yùn)行良好,但是對(duì)于客戶(hù)端比較多的業(yè)務(wù)來(lái)說(shuō),單機(jī)服務(wù)端可能需要支撐成千上萬(wàn)的連接,IO模型可能就不太合適了。這是因?yàn)樵趥鹘y(tǒng)的IO模型中,每個(gè)連接創(chuàng)建成功之后都需要一個(gè)線程來(lái)維護(hù),每個(gè)線程包含一個(gè)while死循環(huán),那么1w個(gè)連接對(duì)應(yīng)1w個(gè)線程,繼而1w個(gè)while死循環(huán),這就帶來(lái)如下幾個(gè)問(wèn)題:

1.線程資源受限:線程是操作系統(tǒng)中非常寶貴的資源,同一時(shí)刻有大量的線程處于阻塞狀態(tài)是非常嚴(yán)重的資源浪費(fèi),操作系統(tǒng)耗不起。

2.線程切換效率低下:?jiǎn)螜C(jī)cpu核數(shù)固定,線程爆炸之后操作系統(tǒng)頻繁進(jìn)行線程切換,應(yīng)用性能急劇下降。

3.除了以上兩個(gè)問(wèn)題,IO編程中,我們看到數(shù)據(jù)讀寫(xiě)是以字節(jié)流為單位,效率不高。

為了解決這三個(gè)問(wèn)題,JDK在1.4之后提出了NIO。下面簡(jiǎn)單描述一下NIO是如何解決以上三個(gè)問(wèn)題的。

線程資源受限

NIO編程模型中,新來(lái)一個(gè)連接不再創(chuàng)建一個(gè)新的線程,而是可以把這條連接直接綁定到某個(gè)固定的線程,然后這條連接所有的讀寫(xiě)都由這個(gè)線程來(lái)負(fù)責(zé)。
這個(gè)過(guò)程的實(shí)現(xiàn)歸功于NIO模型中selector的作用,一條連接來(lái)了之后,現(xiàn)在不創(chuàng)建一個(gè)while死循環(huán)去監(jiān)聽(tīng)是否有數(shù)據(jù)可讀了,而是直接把這條連接注冊(cè)到selector上,然后,通過(guò)檢查這個(gè)selector,就可以批量監(jiān)測(cè)出有數(shù)據(jù)可讀的連接,進(jìn)而讀取數(shù)據(jù)。

線程切換效率低下

由于NIO模型中線程數(shù)量大大降低,線程切換效率因此也大幅度提高。

IO讀寫(xiě)以字節(jié)為單位

NIO解決這個(gè)問(wèn)題的方式是數(shù)據(jù)讀寫(xiě)不再以字節(jié)為單位,而是以字節(jié)塊為單位。IO模型中,每次都是從操作系統(tǒng)底層一個(gè)字節(jié)一個(gè)字節(jié)地讀取數(shù)據(jù),而NIO維護(hù)一個(gè)緩沖區(qū),每次可以從這個(gè)緩沖區(qū)里面讀取一塊的數(shù)據(jù)。




hello netty

完整代碼鏈接:https://github.com/ShimmerPig...

首先定義一對(duì)線程組——主線程bossGroup與從線程workerGroup。
bossGroup——用于接受客戶(hù)端的連接,但是不做任何處理,跟老板一樣,不做事。
workerGroup——bossGroup會(huì)將任務(wù)丟給他,讓workerGroup去處理。

//主線程
EventLoopGroup bossGroup = new NioEventLoopGroup();
//從線程
EventLoopGroup workerGroup = new NioEventLoopGroup();

定義服務(wù)端的啟動(dòng)類(lèi)serverBootstrap,需要設(shè)置主從線程,NIO的雙向通道,與子處理器(用于處理workerGroup),這里的子處理器后面我們會(huì)手動(dòng)創(chuàng)建。

// netty服務(wù)器的創(chuàng)建, ServerBootstrap 是一個(gè)啟動(dòng)類(lèi)
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(bossGroup, workerGroup)            // 設(shè)置主從線程組
                            .channel(NioServerSocketChannel.class)    // 設(shè)置nio的雙向通道
                            .childHandler(new HelloServerInitializer()); // 子處理器,用于處理workerGroup

啟動(dòng)服務(wù)端,綁定8088端口,同時(shí)設(shè)置啟動(dòng)的方式為同步的,這樣我們的Netty就會(huì)一直等待,直到該端口啟動(dòng)完畢。

ChannelFuture channelFuture = serverBootstrap.bind(8088).sync();

監(jiān)聽(tīng)關(guān)閉的通道channel,設(shè)置為同步方式。

channelFuture.channel().closeFuture().sync();

將兩個(gè)線程優(yōu)雅地關(guān)閉。

bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();

創(chuàng)建管道channel的子處理器HelloServerInitializer,用于處理workerGroup。
HelloServerInitializer里面只重寫(xiě)了initChannel方法,是一個(gè)初始化器,channel注冊(cè)后,會(huì)執(zhí)行里面相應(yīng)的初始化方法。
在initChannel方法中通過(guò)SocketChannel獲得對(duì)應(yīng)的管道,通過(guò)該管道添加相關(guān)助手類(lèi)handler。
HttpServerCodec是由netty自己提供的助手類(lèi),可以理解為攔截器,當(dāng)請(qǐng)求到服務(wù)端,我們需要做解碼,響應(yīng)到客戶(hù)端做編碼。
添加自定義的助手類(lèi)customHandler,返回"hello netty~"

ChannelPipeline pipeline = channel.pipeline();
pipeline.addLast("HttpServerCodec", new HttpServerCodec());
pipeline.addLast("customHandler", new CustomHandler());

創(chuàng)建自定義的助手類(lèi)CustomHandler繼承SimpleChannelInboundHandler,返回hello netty~
重寫(xiě)channelRead0方法,首先通過(guò)傳入的上下文對(duì)象ChannelHandlerContext獲取channel,若消息類(lèi)型為http請(qǐng)求,則構(gòu)建一個(gè)內(nèi)容為"hello netty~"的http響應(yīng),通過(guò)上下文對(duì)象的writeAndFlush方法將響應(yīng)刷到客戶(hù)端。

if (msg instanceof HttpRequest) {
    // 顯示客戶(hù)端的遠(yuǎn)程地址
    System.out.println(channel.remoteAddress());
    
    // 定義發(fā)送的數(shù)據(jù)消息
    ByteBuf content = Unpooled.copiedBuffer("Hello netty~", CharsetUtil.UTF_8);
    
    // 構(gòu)建一個(gè)http response
    FullHttpResponse response = 
        new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, 
                HttpResponseStatus.OK, 
                content);
    // 為響應(yīng)增加數(shù)據(jù)類(lèi)型和長(zhǎng)度
    response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain");
    response.headers().set(HttpHeaderNames.CONTENT_LENGTH, content.readableBytes());
    
    // 把響應(yīng)刷到客戶(hù)端
    ctx.writeAndFlush(response);
}

訪問(wèn)8088端口,返回"hello netty~"




netty聊天小練習(xí)

完整代碼鏈接:https://github.com/ShimmerPig...

服務(wù)器

定義主從線程與服務(wù)端的啟動(dòng)類(lèi)

public class WSServer {

    public static void main(String[] args) throws Exception {
        
        EventLoopGroup mainGroup = new NioEventLoopGroup();
        EventLoopGroup subGroup = new NioEventLoopGroup();
        
        try {
            ServerBootstrap server = new ServerBootstrap();
            server.group(mainGroup, subGroup)
                .channel(NioServerSocketChannel.class)
                .childHandler(new WSServerInitialzer());
            
            ChannelFuture future = server.bind(8088).sync();
            
            future.channel().closeFuture().sync();
        } finally {
            mainGroup.shutdownGracefully();
            subGroup.shutdownGracefully();
        }
    }
    
}

創(chuàng)建channel的子處理器WSServerInitialzer
加入相關(guān)的助手類(lèi)handler

public class WSServerInitialzer extends ChannelInitializer {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        
        // websocket 基于http協(xié)議,所以要有http編解碼器
        pipeline.addLast(new HttpServerCodec());
        // 對(duì)寫(xiě)大數(shù)據(jù)流的支持 
        pipeline.addLast(new ChunkedWriteHandler());
        // 對(duì)httpMessage進(jìn)行聚合,聚合成FullHttpRequest或FullHttpResponse
        // 幾乎在netty中的編程,都會(huì)使用到此hanler
        pipeline.addLast(new HttpObjectAggregator(1024*64));
        
        // ====================== 以上是用于支持http協(xié)議    ======================
        
        // ====================== 以下是支持httpWebsocket ======================
        
        /**
         * websocket 服務(wù)器處理的協(xié)議,用于指定給客戶(hù)端連接訪問(wèn)的路由 : /ws
         * 本handler會(huì)幫你處理一些繁重的復(fù)雜的事
         * 會(huì)幫你處理握手動(dòng)作: handshaking(close, ping, pong) ping + pong = 心跳
         * 對(duì)于websocket來(lái)講,都是以frames進(jìn)行傳輸?shù)模煌臄?shù)據(jù)類(lèi)型對(duì)應(yīng)的frames也不同
         */
        pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
        
        // 自定義的handler
        pipeline.addLast(new ChatHandler());
    }

}

創(chuàng)建自定義的助手類(lèi)ChatHandler,用于處理消息。
TextWebSocketFrame:在netty中,是用于為websocket專(zhuān)門(mén)處理文本的對(duì)象,frame是消息的載體。
創(chuàng)建管道組ChannelGroup,用于管理所有客戶(hù)端的管道channel。

private static ChannelGroup clients = 
    new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

重寫(xiě)channelRead0方法,通過(guò)傳入的TextWebSocketFrame獲取客戶(hù)端傳入的內(nèi)容。通過(guò)循環(huán)的方法對(duì)ChannelGroup中所有的channel進(jìn)行回復(fù)。

@Override
protected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) 
throws Exception {
    // 獲取客戶(hù)端傳輸過(guò)來(lái)的消息
    String content = msg.text();
    System.out.println("接受到的數(shù)據(jù):" + content);

//        for (Channel channel: clients) {
//            channel.writeAndFlush(
//                new TextWebSocketFrame(
//                        "[服務(wù)器在]" + LocalDateTime.now() 
//                        + "接受到消息, 消息為:" + content));
//        }
    // 下面這個(gè)方法,和上面的for循環(huán),一致
    clients.writeAndFlush(
    new TextWebSocketFrame(
            "[服務(wù)器在]" + LocalDateTime.now() 
            + "接受到消息, 消息為:" + content));

}

重寫(xiě)handlerAdded方法,當(dāng)客戶(hù)端連接服務(wù)端之后(打開(kāi)連接),獲取客戶(hù)端的channle,并且放到ChannelGroup中去進(jìn)行管理。

@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
    clients.add(ctx.channel());
}

重寫(xiě)handlerRemoved方法,當(dāng)觸發(fā)handlerRemoved,ChannelGroup會(huì)自動(dòng)移除對(duì)應(yīng)客戶(hù)端的channel。

@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
    // 當(dāng)觸發(fā)handlerRemoved,ChannelGroup會(huì)自動(dòng)移除對(duì)應(yīng)客戶(hù)端的channel
    //        clients.remove(ctx.channel());
    System.out.println("客戶(hù)端斷開(kāi),channle對(duì)應(yīng)的長(zhǎng)id為:" 
                + ctx.channel().id().asLongText());
    System.out.println("客戶(hù)端斷開(kāi),channle對(duì)應(yīng)的短id為:" 
                            + ctx.channel().id().asShortText());
}
客戶(hù)端


    
        
        
    
    
        
        
發(fā)送消息:
接受消息:




測(cè)試

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/101650.html

相關(guān)文章

  • Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App詳解(四)

    Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目介紹。Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目github鏈接。本章完整代碼鏈接。 本章內(nèi)容 (1) 查詢(xún)好友列表的接口 (2)通過(guò)或忽略好友請(qǐng)求的接口 (3)添加好友功能展示 查詢(xún)好友列表的接口 /** * @Description: 查詢(xún)我的好友列表 ...

    why_rookie 評(píng)論0 收藏0
  • Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App詳解(三)

    摘要:實(shí)現(xiàn)聊天,項(xiàng)目介紹。首先根據(jù)搜索的用戶(hù)的名稱(chēng)查找是否存在這個(gè)用戶(hù)。如果搜索前置條件為成功,則向前端返回搜索用戶(hù)的信息。發(fā)送添加好友的請(qǐng)求判斷不能為空查詢(xún)用戶(hù)接受到的朋友申請(qǐng)最終實(shí)現(xiàn)效果 Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目介紹。Netty+SpringBoot+FastDFS+Html5實(shí)現(xiàn)聊天App,項(xiàng)目github鏈接。本章完整代碼鏈接。...

    isLishude 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<