亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

netty搭建web聊天室(1)

izhuhaodev / 3388人閱讀

摘要:提供異步的事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架和工具,用以快速開(kāi)發(fā)高性能高可靠性的網(wǎng)絡(luò)服務(wù)器和客戶端程序??偨Y(jié)我們完成了服務(wù)端的簡(jiǎn)單搭建,模擬了聊天會(huì)話場(chǎng)景。

之前一直在搞前端的東西,都快忘了自己是個(gè)java開(kāi)發(fā)。其實(shí)還有好多java方面的東西沒(méi)搞過(guò),突然了解到netty,覺(jué)得有必要學(xué)一學(xué)。
介紹

Netty是由JBOSS提供的一個(gè)java開(kāi)源框架。Netty提供異步的、事件驅(qū)動(dòng)的網(wǎng)絡(luò)應(yīng)用程序框架和工具,用以快速開(kāi)發(fā)高性能、高可靠性的網(wǎng)絡(luò)服務(wù)器和客戶端程序。

也就是說(shuō),Netty 是一個(gè)基于NIO的客戶、服務(wù)器端編程框架,使用Netty 可以確保你快速和簡(jiǎn)單的開(kāi)發(fā)出一個(gè)網(wǎng)絡(luò)應(yīng)用,例如實(shí)現(xiàn)了某種協(xié)議的客戶、服務(wù)端應(yīng)用。Netty相當(dāng)于簡(jiǎn)化和流線化了網(wǎng)絡(luò)應(yīng)用的編程開(kāi)發(fā)過(guò)程,例如:基于TCP和UDP的socket服務(wù)開(kāi)發(fā)。

一些IO概念

NIO (non-blocking IO) 非阻塞

BIO (blocking IO) 阻塞

以上兩種又可分為同步和異步,即同步阻塞,同步非阻塞,異步阻塞,異步非阻塞。

阻塞:數(shù)據(jù)沒(méi)來(lái),啥都不做,直到數(shù)據(jù)來(lái)了,才進(jìn)行下一步的處理。

非阻塞:數(shù)據(jù)沒(méi)來(lái),進(jìn)程就不停的去檢測(cè)數(shù)據(jù),直到數(shù)據(jù)來(lái)。

至于這塊的詳細(xì)概念,大家可以自行百度學(xué)習(xí)??傊琻etty處理io很高效,不需要你擔(dān)心。

netty結(jié)構(gòu)

可以看出它支持的網(wǎng)絡(luò)傳輸協(xié)議,以及容器支持,安全支持,io.

工作流程:
所有客戶端的連接交給住主線程去管理,響應(yīng)客戶端的消息交給從線程去處理,整個(gè)線程池由netty負(fù)責(zé)。

搭建服務(wù)

創(chuàng)建maven工程引入最新的依賴


    4.0.0
    com.mike
    netty
    0.0.1-SNAPSHOT

    
        UTF-8
        1.8
    

    
        
            io.netty
            netty-all
            4.1.32.Final
        
    

創(chuàng)建消息處理器

package netty;

import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http2.Http2Headers;
import io.netty.util.concurrent.GlobalEventExecutor;

/**
 * 
 */
public class ChatHandler extends SimpleChannelInboundHandler{
    
    public static ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
    
    /**
     * 每當(dāng)從服務(wù)端收到新的客戶端連接時(shí),客戶端的 Channel 存入ChannelGroup列表中,并通知列表中的其他客戶端 Channel
     */
    @Override
    public void handlerAdded(ChannelHandlerContext ctx) throws Exception {  
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 加入
");
        }
        channels.add(ctx.channel());
    }
    
    /**
     * 每當(dāng)從服務(wù)端收到客戶端斷開(kāi)時(shí),客戶端的 Channel 移除 ChannelGroup 列表中,并通知列表中的其他客戶端 Channel
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {  
        Channel incoming = ctx.channel();
        for (Channel channel : channels) {
            channel.writeAndFlush("[SERVER] - " + incoming.remoteAddress() + " 離開(kāi)
");
        }
        channels.remove(ctx.channel());
    }
    
    /**
     * 會(huì)話建立時(shí)
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)
        Channel incoming = ctx.channel();
        System.out.println("ChatClient:"+incoming.remoteAddress()+"在線");
    }
    
    /**
     * 會(huì)話結(jié)束時(shí)
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)
        Channel incoming = ctx.channel();
        System.out.println("ChatClient:"+incoming.remoteAddress()+"掉線");
    }
    
    /**
     * 出現(xiàn)異常
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { // (7)
        Channel incoming = ctx.channel();
        System.out.println("ChatClient:"+incoming.remoteAddress()+"異常");
        // 當(dāng)出現(xiàn)異常就關(guān)閉連接
        cause.printStackTrace();
        ctx.close();
    }
    
    /**
     * 讀取客戶端發(fā)送的消息,并將信息轉(zhuǎn)發(fā)給其他客戶端的 Channel。
     */
    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Object  request) throws Exception {
            FullHttpResponse response = new DefaultFullHttpResponse(
                    HttpVersion.HTTP_1_1,HttpResponseStatus.OK , Unpooled.wrappedBuffer("Hello netty"
                            .getBytes()));
            response.headers().set("Content-Type", "text/plain");
            response.headers().set("Content-Length", response.content().readableBytes());
            response.headers().set("connection", HttpHeaderValues.KEEP_ALIVE);
            ctx.writeAndFlush(response);
        
    }

}

這里面其實(shí)只需要重寫channelRead0 方法就可以了,其他是它的生命周期的方法,可以用來(lái)做日至記錄。我們?cè)谧x取消息后,往channel里寫入了一個(gè)http的response。

初始化我們的消息處理器

package netty;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

/**
 * 用來(lái)增加多個(gè)的處理類到 ChannelPipeline 上,包括編碼、解碼、SimpleChatServerHandler 等。
 */
public class ChatServerInitializer extends ChannelInitializer{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
            ChannelPipeline pipeline = ch.pipeline();
            pipeline.addLast("HttpResponseEncoder",new HttpResponseEncoder());
            pipeline.addLast("HttpRequestDecoder",new HttpRequestDecoder());
            pipeline.addLast("chathandler", new ChatHandler());

            System.out.println("ChatClient:"+ch.remoteAddress() +"連接上");
        
    }

}

這個(gè)pipeline可以理解為netty的攔截器,每個(gè)消息進(jìn)來(lái),經(jīng)過(guò)各個(gè)攔截器的處理。我們需要響應(yīng)http消息,所以加入了響應(yīng)編碼以及請(qǐng)求解碼,最后加上了我們的自定義處理器。這里面有很多處理器,netty以及幫你定義好的。

服務(wù)啟動(dòng)類

package netty;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;

/**
 * The class ChatServer
 */
public class ChatServer {
      private int port;

        public ChatServer(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 ChatServerInitializer())  
                 .option(ChannelOption.SO_BACKLOG, 128)          
                 .childOption(ChannelOption.SO_KEEPALIVE, true); 

                System.out.println("ChatServer 啟動(dòng)了");

                // 綁定端口,開(kāi)始接收進(jìn)來(lái)的連接
                ChannelFuture f = b.bind(port).sync(); // (7)

                // 等待服務(wù)器  socket 關(guān)閉 。
                // 在這個(gè)例子中,這不會(huì)發(fā)生,但你可以優(yōu)雅地關(guān)閉你的服務(wù)器。
                f.channel().closeFuture().sync();

            } finally {
                workerGroup.shutdownGracefully();
                bossGroup.shutdownGracefully();

                System.out.println("ChatServer 關(guān)閉了");
            }
        }

        public static void main(String[] args) throws Exception {
            new ChatServer(8090).run();

        }
}

這個(gè)啟動(dòng)類就是按照上面那個(gè)結(jié)構(gòu)圖來(lái)的,添加兩個(gè)線程組,設(shè)置channel,添加消息處理器,配置一些選項(xiàng)option。

測(cè)試

啟動(dòng)程序,瀏覽器訪問(wèn) http://localhost:8090

可以在瀏覽器看到我們返回的消息,但是控制臺(tái)卻顯示連接了多個(gè)客戶端,其實(shí)是因?yàn)闉g覽器發(fā)送了無(wú)關(guān)的請(qǐng)求道服務(wù)端,由于我們沒(méi)有做路由,所以所有請(qǐng)求都是200。

可以看到,發(fā)送了兩次請(qǐng)求?,F(xiàn)在我們換postman測(cè)試。

這次只有一個(gè)客戶端連接,當(dāng)我們關(guān)閉postman:

客戶端顯示掉線,整個(gè)會(huì)話過(guò)程結(jié)束。

總結(jié)

我們完成了服務(wù)端的簡(jiǎn)單搭建,模擬了聊天會(huì)話場(chǎng)景。后面再接著完善。

別忘了關(guān)注我 mike啥都想搞

還有其他后端技術(shù)分享在我的公眾號(hào)。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/73106.html

相關(guān)文章

  • netty搭建web天室(3)單聊

    摘要:開(kāi)始聊天發(fā)送聊天信息時(shí)消息,這樣后端就知道是誰(shuí)要發(fā)給誰(shuí),根據(jù)用戶名去找到具體的線程去單獨(dú)推送消息,實(shí)現(xiàn)單聊。前端待完善左側(cè)聊天列表沒(méi)有實(shí)現(xiàn),每搜索一個(gè)在線用戶,應(yīng)該動(dòng)態(tài)顯示在左側(cè),點(diǎn)擊該用戶,動(dòng)態(tài)顯示右側(cè)聊天窗口進(jìn)行消息發(fā)送。 上節(jié)課講了群聊,這次來(lái)說(shuō)說(shuō)單聊,單聊要比群聊復(fù)雜點(diǎn),但是代碼也不是很多,主要是前端顯示比較麻煩點(diǎn)。 效果:showImg(https://segmentfaul...

    Lavender 評(píng)論0 收藏0
  • netty搭建web天室(2)群聊

    摘要:上節(jié)課完成了的后端搭建,搞定了簡(jiǎn)單的請(qǐng)求響應(yīng),今天來(lái)結(jié)合前端來(lái)完成群聊功能。其實(shí)后端群聊很簡(jiǎn)單,就是把一個(gè)用戶的輸入消息,返回給所有在線客戶端,前端去負(fù)責(zé)篩選顯示。 上節(jié)課完成了netty的后端搭建,搞定了簡(jiǎn)單的http請(qǐng)求響應(yīng),今天來(lái)結(jié)合前端websocket來(lái)完成群聊功能。話不多說(shuō)先上圖:showImg(https://segmentfault.com/img/bVbnCa8?w=...

    microelec 評(píng)論0 收藏0
  • 不發(fā)不行!Netty集成文字圖片天室外加TCP/IP軟硬件通信

    摘要:前言熬了一晚上硬是磨出來(lái)了,更新到了上,善存一些小,不過(guò)這個(gè)版本的整體功能算是實(shí)現(xiàn)了。預(yù)留其余的就是可能善存的一些了圖片過(guò)大,需要在前端做圖片上傳壓縮前端代碼的一點(diǎn)問(wèn)題,不影響項(xiàng)目正常運(yùn)行遠(yuǎn)程主機(jī)強(qiáng)迫關(guān)閉了一個(gè)現(xiàn)有的連接。 前言 熬了一晚上硬是磨出來(lái)了,更新到了GitHub上,善存一些小BUG,不過(guò)這個(gè)版本的整體功能算是實(shí)現(xiàn)了。 項(xiàng)目:UncleCatMySelf/InChat 地址:...

    siberiawolf 評(píng)論0 收藏0
  • 用Java構(gòu)建一個(gè)簡(jiǎn)單的WebSocket聊天項(xiàng)目之新增HTTP接口調(diào)度

    摘要:前言大家可以看看上一篇用構(gòu)建一個(gè)簡(jiǎn)單的聊天室在上一篇文章中我們已經(jīng)實(shí)現(xiàn)了自我對(duì)話好友交流群聊離線消息等的功能。系統(tǒng)通知恭喜您連續(xù)登錄超過(guò)天,獎(jiǎng)勵(lì)積分。 本文首發(fā)公眾號(hào)與個(gè)人博客:Java貓說(shuō) & 貓叔的博客 | MySelf,轉(zhuǎn)載請(qǐng)申明出處。 前言 大家可以看看上一篇:用Java構(gòu)建一個(gè)簡(jiǎn)單的WebSocket聊天室 在上一篇文章中我們已經(jīng)實(shí)現(xiàn)了:自我對(duì)話、好友交流、群聊、離線消息等...

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

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

0條評(píng)論

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