【Netty源码分析】03 客户端接入流程-每日消息

2023-03-29 15:31:54 来源: 腾讯云

Netty服务端启动完成,这时候客户端连接就可以接入进来了,下面我们就来分析下客户端连接接入的流程。

之前分析过NioEventLoop线程启动方法是startThread(),由于这个方法里面的逻辑比较复杂,并没有展开,这一节就是从这个方法开始分析。

startThread

private void startThread() {    if (state == ST_NOT_STARTED) {        if (STATE_UPDATER.compareAndSet(this, ST_NOT_STARTED, ST_STARTED)) {            try {                doStartThread();            } catch (Throwable cause) {                STATE_UPDATER.set(this, ST_NOT_STARTED);                PlatformDependent.throwException(cause);            }        }    }}

这个方法主要主要完成2件事:


(资料图)

利用casNioEventLoop的状态由ST_NOT_STARTED修改成ST_STARTED,即表示NioEventLoop线程启动;执行doStartThread()方法;

doStartThread()方法看着比较复杂,核心逻辑如下,向线程池执行器executor提交一个任务,而这个线程池执行器类型是ThreadPerTaskExecutor,即每次执行任务都会创建一个新线程,而且这个任务是无限循环的:事件轮询selector.select()、事件处理processSelectedKeys()和任务队列处理runAllTasks(),这样NioEventLoop就和具体的Thread线程进行了关联:

private void doStartThread() {    assert thread == null;    //executor线程执行器,类型是:ThreadPerTaskExecutor,即每次执行任务都会创建一个新线程    executor.execute(new Runnable() {        @Override        public void run() {            //将executor线程执行器创建的线程:FastThreadLocalThread保存到EventLoop的全局变量中,相当于thread和EventLoop的绑定            thread = Thread.currentThread();            if (interrupted) {                thread.interrupt();            }            boolean success = false;            updateLastExecutionTime();            try {                //然后调用EventLoop中的run方法进行启动                SingleThreadEventExecutor.this.run();                success = true;            } catch (Throwable t) {                logger.warn("Unexpected exception from an event executor: ", t);            }        }    });}

该方法大致完成2件事:

thread = Thread.currentThread();:将executor线程池分配的线程保存起来,这样就完成了NioEventLoopThread线程的关联;SingleThreadEventExecutor.this.run():具体实现在NioEventLoop.run()方法,所以,startThread()核心就是分配一个线程运行NioEventLoop.run()方法。
protected void run() {    for (;;) {        try {            try {                switch (selectStrategy.calculateStrategy(selectNowSupplier, hasTasks())) {                case SelectStrategy.CONTINUE:// 默认实现下,不存在这个情况                    continue;                case SelectStrategy.BUSY_WAIT:                case SelectStrategy.SELECT:                    //selector.select轮询io事件                    select(wakenUp.getAndSet(false));                    if (wakenUp.get()) {                        selector.wakeup();                    }                default:                }            } catch (IOException e) {                rebuildSelector0();                handleLoopException(e);                continue;            }            cancelledKeys = 0;            needsToSelectAgain = false;            final int ioRatio = this.ioRatio;            if (ioRatio == 100) {               try {                    // 处理 Channel 感兴趣的就绪 IO 事件                    processSelectedKeys();                } finally {                    // 运行所有普通任务和定时任务,不限制时间                    runAllTasks();                }            } else {                final long ioStartTime = System.nanoTime();                try {                    // 处理IO事件                    processSelectedKeys();                } finally {                    // 运行所有普通任务和定时任务,限制时间                    final long ioTime = System.nanoTime() - ioStartTime;                    runAllTasks(ioTime * (100 - ioRatio) / ioRatio);                }            }        } catch (Throwable t) {            handleLoopException(t);        }        //  EventLoop 优雅关闭        try {            if (isShuttingDown()) {                closeAll();                if (confirmShutdown()) {                    return;                }            }        } catch (Throwable t) {            handleLoopException(t);        }    }}

该方法主要完成三件事:

select(wakenUp.getAndSet(false)):主要执行selector.select()方法进行事件轮询processSelectedKeys():如果轮询到事件,会在这里进行处理runAllTasks():处理任务队列和定时任务队列中的任务

下面我们就分别来分析下这三个方法。

select

private void select(boolean oldWakenUp) throws IOException {    Selector selector = this.selector;    try {        int selectCnt = 0;//计数器置0        long currentTimeNanos = System.nanoTime();        /**         * selectDeadLineNanos是select()方法运行的截止时间         *         * currentTimeNanos:可以看成当前时间         * delayNanos(currentTimeNanos):获取间隔时间,这里分为两种情况:         * 1、netty里面定时任务队列scheduledTaskQueue是按照延迟时间从小到大进行排序,如果定时任务队列中有任务,         * 则只需要获取到第一个任务的启动时间 - 当前时间 = select()方法可以运行的时间间隔,即:select()方法要在第一个定时任务执行之前退出,这样才能去执行定时任务         * 2、如果定时任务队列没有任务,则delayNanos(currentTimeNanos)返回1秒对应的时间间隔         *         */        long selectDeadLineNanos = currentTimeNanos + delayNanos(currentTimeNanos);        for (;;) {            //计算超时时间            long timeoutMillis = (selectDeadLineNanos - currentTimeNanos + 500000L) / 1000000L;            /**             * timeoutMillis <= 0表示当前已经超时了,不能继续向下执行select()方法了,需要立即退出select方法,在退出前还有个判断:selectCnt == 0             * selectCnt == 0表示第一次进入循环,则执行下Selector.selectNow()检出准备好的网络IO事件,该方法不会阻塞,             */            if (timeoutMillis <= 0) {                if (selectCnt == 0) {                    selector.selectNow();                    selectCnt = 1;                }                break;            }            /**             * 如果没有超时,但是通过hasTasks()判断到taskQueue任务队列中有需要执行的任务,这时也需要退出select()方法             * 1、利用cas将wakeUp值由false变成true,wakeUp=true表示线程处于唤醒状态,可以执行任务,进入select()方法前会把wakeUp设置成false             * 表示线程处于select()方法阻塞中,不能处理任务队列中的任务,这时只要处理Selector.select()             * 2、退出前执行一次:selector.selectNow()             */            if (hasTasks() && wakenUp.compareAndSet(false, true)) {                //有任务,进行一次非阻塞式的select                selector.selectNow();                selectCnt = 1;                break;            }            //调用select方法,阻塞时间为上面算出的最近一个将要超时的定时任务时间            /**             * 未超时,任务队列中也没有需要执行的任务,这时就可以放心的执行Selector.select()方法了,这里带上之前计算出的超时时间             * 如果之前计算时存在定时任务,则保证在第一个定时任务启动前唤醒即可,没有定时任务则默认超时1秒             */            int selectedKeys = selector.select(timeoutMillis);            //轮询次数+1            selectCnt ++;            /**             * 发生如下几种情况,select()方法都需要退出:             * 1、selectedKeys != 0:表示轮询到IO事件             * 2、oldWakenUp:这个是入参,值为false,是在select()方法中控制是否需要退出,默认是没有使用到的,没有意义             * 3、wakenUp.get():进入select()方法之前,wakeUp被设置成false,如果这里为true,表示已有外部线程对线程进行唤醒操作,             *      一般就是addTask()添加新任务时会触发唤醒,然后及时去执行taskQueue中的任务             * 4、hasTasks() || hasScheduledTasks():判断任务队列和定时任务队列是否有任务需要执行             */            if (selectedKeys != 0 || oldWakenUp || wakenUp.get() || hasTasks() || hasScheduledTasks()) {                break;            }            //线程中断响应:如果线程被中断,计数器置1,break退出for循环,则退出select()检测            if (Thread.interrupted()) {                if (logger.isDebugEnabled()) {                    logger.debug("Selector.select() returned prematurely because " +                            "Thread.currentThread().interrupt() was called. Use " +                            "NioEventLoop.shutdownGracefully() to shutdown the NioEventLoop.");                }                selectCnt = 1;                break;            }            /**             * 正常情况下:time >= currentTimeNanos + TimeUnit.MILLISECONDS.toNanos(timeoutMillis)             * 但是,jdk nio中存在一个bug,selector.select(timeoutMillis)在没有IO事件触发时并不会等待超时而是立即返回,造成空轮询             *             * 下面就是Netty解决空轮询问题             * 1、if (time - TimeUnit.MILLISECONDS.toNanos(timeoutMillis) >= currentTimeNanos)             *      表示selector.select(timeoutMillis)经过超时后才被唤醒,属于正常情况,把selectCnt重置成1             * 2、如果不是,表示可能发生空轮询selectCnt不会被重置成1,for循环一次selectCnt就会被累加1次;             * 3、等到 selectCnt > 门限值,默认是512,可以通过io.netty.selectorAutoRebuildThreshold参数设置,             *      则判断真正发生了nio空循环bug,则重建Selector替换掉当前这个出问题的Selector             */            long time = System.nanoTime();            //判断执行了一次阻塞式select后,当前时间和开始时间是否大于超时时间。(大于是很正常的,小于的话,说明没有执行发生了空轮询)            if (time - TimeUnit.MILLISECONDS.toNanos(timeoutMillis) >= currentTimeNanos) {                selectCnt = 1;             } else if (SELECTOR_AUTO_REBUILD_THRESHOLD > 0 &&                    selectCnt >= SELECTOR_AUTO_REBUILD_THRESHOLD) {                selector = selectRebuildSelector(selectCnt);                selectCnt = 1;                break;            }            currentTimeNanos = time;        }    } catch (CancelledKeyException e) {        if (logger.isDebugEnabled()) {            logger.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector {} - JDK bug?",                        selector, e);        }    }}

select()方法代码看着很复杂,其核心思想理解再来分析就比较简单的。select()主要是用来执行selector.select()IO事件进行轮询,作为server,这里就是轮询OP_ACCEPT事件,看是否有客户端接入进来。但是NioEventLoop是单线程处理模式,不可能让线程一直处理selector.select(),还有轮询到的事件以及任务队列中任务等等都需要使用这个线程进行处理,所以,上面一大堆代码都是用来判断什么时候退出select()方法的,总结下退出逻辑主要分为如下几种情况:

在执行selector.select()方法之前,计算出一个超时时间,超时时间默认是1秒,如果定时任务队列有任务,则取出第一个任务(按顺序存放),保证在该定时任务执行之前退出select()方法即可;如果超时就退出,退出前判断是否是第一次进入for循环,如果是在退出之前调用一次无阻塞的selector.selectNow()轮询下判断任务队列taskQueue中是否有任务,如果有则将wakenUp利用cas设置成true,执行下无阻塞的selector.selectNow()轮询后退出select()方法如果上面情况都不存在,开始执行阻塞selector.select(timeoutMillis)轮询,并将之前计算的超时时间带上;selector.select(timeoutMillis)执行完成后,继续判断是否需要退出select()方法,发生如下任一情况则要退出:轮询到IO事件,则需要退出select()方法去处理事件外部线程对对线程执行过唤醒操作,比如addTask()等操作需要唤醒线程执行队列任务,才能及时去执行taskQueue中的任务:进入select()方法之前,wakeUp被设置成false,如果这里为true,表示已有外部线程对线程进行唤醒操作任务队列taskQueue或定时任务队列scheduledTaskQueue中有需要处理的任务,这时需要退出select()方法,转去执行任务

processSelectedKeys

private void processSelectedKeys() {    //selectedKeys != null表示已对Selector进行优化过,替换掉Selector内部的selectedKeys,正常情况下进入这个流程    if (selectedKeys != null) {        processSelectedKeysOptimized();    } else {        processSelectedKeysPlain(selector.selectedKeys());    } }

processSelectedKeys()主要是对selector.select()方法轮询到的事件进行处理,作为server,如果轮询到OP_ACCEPT,就表示有客户端接入进来了,那我们就跟踪下这个方法,看接入进来的客户端处理流程。

Netty是对Selector进行了优化,将selectedKeysSet实现替换成了数组实现,提升性能,所以,这里一般走的是processSelectedKeysOptimized()这个流程:

private void processSelectedKeysOptimized() {    for (int i = 0; i < selectedKeys.size; ++i) {        final SelectionKey k = selectedKeys.keys[i];        selectedKeys.keys[i] = null;        //k.attachment()获取到的就是NioServerSocketChannel        final Object a = k.attachment();        if (a instanceof AbstractNioChannel) {//一般是走这个分支流程            processSelectedKey(k, (AbstractNioChannel) a);        } else {            @SuppressWarnings("unchecked")            NioTask task = (NioTask) a;            processSelectedKey(k, task);        }        if (needsToSelectAgain) {            selectedKeys.reset(i + 1);            selectAgain();            i = -1;        }    }}

这里关键一点是Object a = k.attachment();,之前分析过向selector注册时把NioServerSocketChannel作为attachment添加进去,所以,这里取出来的就是NioServerSocketChannel对象。processSelectedKey()方法通过if判断事件类型进行处理,server端这里肯定是OP_ACCEPT

if ((readyOps & (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT)) != 0 || readyOps == 0) { unsafe.read();}

具体的处理逻辑交由Unsafe对象进行处理:

public void read() {    assert eventLoop().inEventLoop();    final ChannelConfig config = config();    final ChannelPipeline pipeline = pipeline();    final RecvByteBufAllocator.Handle allocHandle = unsafe().recvBufAllocHandle();    allocHandle.reset(config);    boolean closed = false;    Throwable exception = null;    try {        try {            do {                //doReadMessages()读出来一个客户端连接的Channel                int localRead = doReadMessages(readBuf);                if (localRead == 0) {                    break;                }                if (localRead < 0) {                    closed = true;                    break;                }                allocHandle.incMessagesRead(localRead);            } while (allocHandle.continueReading());        } catch (Throwable t) {            exception = t;        }        int size = readBuf.size();        for (int i = 0; i < size; i ++) {            readPending = false;            pipeline.fireChannelRead(readBuf.get(i));        }        readBuf.clear();        allocHandle.readComplete();        pipeline.fireChannelReadComplete();        if (exception != null) {            closed = closeOnReadError(exception);            pipeline.fireExceptionCaught(exception);        }        if (closed) {            inputShutdown = true;            if (isOpen()) {                close(voidPromise());            }        }    } finally {        if (!readPending && !config.isAutoRead()) {            removeReadOp();        }    }}

这个类主要完成2件事:

doReadMessages(readBuf):调用serverSocketChannel.accept()接收到客户端连接socketChannel,并封装成Netty中类型:NioSocketChannel,然后放入到readBuf集合中;pipeline.fireChannelRead(readBuf.get(i));:将读入的客户端连接作为参数,即NioSocketChannel对象,通过pipeline触发channelRead事件进行handler间传播,注意这里的pipelineNioServerSocketChannel中的,即server端的。最终会进入到ServerBootstrapAcceptor#channelRead方法中进行处理。
public void channelRead(ChannelHandlerContext ctx, Object msg) {    final Channel child = (Channel) msg;    child.pipeline().addLast(childHandler);    setChannelOptions(child, childOptions, logger);    for (Entry, Object> e: childAttrs) {        child.attr((AttributeKey) e.getKey()).set(e.getValue());    }    try {        //childGroup.register(child):会给客户端连接进来的Channel从线程池中获取一个EventLoop绑定给Channel        childGroup.register(child).addListener(new ChannelFutureListener() {            @Override            public void operationComplete(ChannelFuture future) throws Exception {                if (!future.isSuccess()) {                    forceClose(child, future.cause());                }            }        });    } catch (Throwable t) {        forceClose(child, t);    }}

这个方法主要完成3件事:

child.pipeline().addLast(childHandler):向NioSocketChannel中添加ServerBootstrap.childHandler(new TestServerInitializer()),后面通过触发handlerAdded()时回调initChannel()实现向pipeline添加handler;设置optionattr信息;childGroup.register(child):将客户端连接NioSocketChannel注册到NioEventLoop实例上,基本和之前分析NioServerSocketChannel注册逻辑一致,这个过程中会触发三个事件:handlerAddedchannelRegisteredchannelActive,之前NioServerSocketChannel注册时只能触发前两个,绑定端口后才能触发第三个事件,客户端连接不存在端口绑定问题,所以这里会直接触发channelActive。和NioServerSocketChannel一样,真正向selector注册感兴趣事件就是在channelActive触发这里:
public void channelActive(ChannelHandlerContext ctx) {    //触发channelActive事件传播    ctx.fireChannelActive();    //向selector注册真正关注的事件    readIfIsAutoRead();}

channelActive和之前分析NioServerSocketChannel的处理逻辑一致,就不再分析。

总结

分析到这里,基本搞清楚了客户端接入的处理流程,现在再次总结下:

NioServerSocketChannel绑定的NioEventLoop不停轮询OP_ACCEPT,触发后通过调用java api获取到ServerSocket,然后包装成NioSocketChannel;然后触发channelRead事件传播,然后会进入server pipeline中非常重要的一个handlerServerBootstrapAcceptor,连接处理器专门处理客户端连接;在ServerBootstrapAcceptor#channelRead()方法中,完成NioSocketChannel的设置:optionattrhandler添加等;最重要的是将channel注册到NioEventLoop上,注册过程中会触发三种事件:handlerAddedchannelRegisteredchannelActive,和之前分析server channel注册过程一样,最终在channelActive这里向selector注册真正感兴趣IO事件,整个流程全部完成。

标签:

上一篇 :

下一篇 :

【Netty源码分析】03 客户端接入流程-每日消息

Netty服务端启动完成,这时候客户端连接就可以接入进来了,下面我们就来分析下客户端连接接入的流程。

03-29 15:31:54

每日速看!以赛提技培育数字产业工人“第一方阵”

近日,福建第二届数字工匠技能大赛在厦门启动。这项福建省单项规模最大、科技含量十足的职业技能大赛将...

03-29 14:42:39

西安雁塔保租房附近学校盘点(幼儿园+初中+小学)

一、周边学校1、西安电子科技大学附中雁塔区太白南路2号西安电子科技大学社区029-882025342、西安电子科...

03-29 13:10:08

盗窃罪量刑标准是什么?抢劫罪与盗窃罪数额的区别是什么?

一、盗窃罪的数额标准盗窃公私财物价值一千元至三千元以上、三万元至十万元以上、三十万元至五十万元以...

03-29 12:11:40

任天堂 Wii 模拟器 Dolphin 将于今年第 2 季度登陆 Steam 平台|天天消息

IT之家3月29日消息,Dolphin模拟器即将于2023年第2季度登陆Steam平台。该团队表示

03-29 11:42:24

【贯彻二十大精神 延安在行动】延安:科学春耕春管 打好丰收基础

【贯彻二十大精神延安在行动】延安:科学春耕春管打好丰收基础

03-29 10:59:28

一刻钟便民生活圈建设加快推进 一刻钟 “圈”出美好生活-世界快播

春光正好,早晨7时,北京市朝阳区红庙北里社区,渐渐涌起热闹的人声。头戴灰色帽子、身穿紫色外套的蔡女...

03-29 10:11:56

高架上出了事故,才知驾照已被扣13分

高架上出了事故,才知驾照已被扣13分,去年11月底,童师傅加入T3出行,做网约车司机。今年1月份,他在高...

03-29 09:05:39

三叶草生物-B(02197.HK)发布年度业绩,股东应占亏损24.52亿元 同比收窄59.25%

三叶草生物-B(02197 HK)发布截至2022年12月31日止年度业绩,该集团取得其他收入及收益人民币2324 6万...

03-29 08:17:26

杀疯了!1TB M.2固态硬盘低至288元

KOOTION酷霄X15M 2接口固态硬盘1TB(PCIe3 0)当前活动价319元,领取满减10元叠加满减21元优惠券,折...

03-29 06:11:03

可持续发展的基本原则是_可持续发展的基本原则主要包括_ 环球精选

1、可持续发展以自然资源为基础,同环境承载能力相协调,其主要有以下原则:  (一)公平性原则可持续...

03-29 01:41:11

厨电2023:一面混战,一面集中|当前热文

作者:叶蓁原创:深眸财经(chutou0325)厨电领域大概是马太效应最弱的领域。大部分家电品类成熟后,市...

03-28 23:08:00

“我可能是最后一次登长城了”,一封从青岛寄到绍兴公安局的信,只因为一个约定_世界热文

“我可能是最后一次登长城了”,一封从青岛寄到绍兴公安局的信,只因为一个约定

03-28 21:11:23

河北保定市联西教育集团:融汇优质资源探路创新人才培养 重点聚焦

参观现代农业体验中心、实验实训中心的生命实验教学平台、交管实验教学平台,聆听博士老师的实验课……...

03-28 20:00:38

【A-SOUL制作委员会的双周QA 03.28】|当前热文

小伙伴们大家好~欢迎来到QA环节以下内容为本期QA的具体内容请小伙伴们往下阅读吧~Q:第八期船员福利有问...

03-28 19:10:47

工信部:引导和支持民营企业、平台企业参与国家重大科技创新 打造世界级数字产业集群

证券时报网讯,据工信微报消息,3月28日,第三届两化融合暨数字化转型大会在江苏苏州召开,工业和信息化...

03-28 18:07:53

连衣裙用英语怎么写_连衣裙的英文是什么

欢迎观看本篇文章,小勉来为大家解答以上问题。连衣裙用英语怎么写,连衣裙的英文是什么很多人还不知道...

03-28 17:06:32

天天新消息丨想看客观评价的进来

让我说什么呢,看完路温的影评来看的深海,没抱什么心态吧,自己一个人搁家里看的,一定没有电影院那种...

03-28 16:04:42

2023贵州“粤港澳大湾区桥头堡”系列赛(黎平站)暨2023“跑乡村·助振兴”中国传统村落(黔东南)健身休闲大会举行

2023贵州“粤港澳大湾区桥头堡”系列赛(黎平站)暨2023“跑乡村·助振兴”中国传统村落(黔东南)健身...

03-28 15:01:32

焦点热文:爱丽丝镜中世界奇遇记英文版_爱丽丝镜中世界奇遇记

1、《爱丽丝镜中奇遇记》是由英国著名作家刘易斯·卡洛尔写的。2、它是一本非常有趣的童话故事书。3、我...

03-28 14:12:05

世界速看:【Spring源码】- 05 扩展点之BeanPostProcessor

BeanPostProcessor和BeanFactoryPostProcessor是Spring中两个最重要的扩展的。如果说BeanFactoryPostPr

03-28 12:09:22

欠钱怎么构成诈骗案

欠钱构成诈骗案一般是看行为人在主观上是否存在以非法占有的目的虚构事实、隐瞒真相骗取数额较大的公私...

03-28 11:20:15

【天天新要闻】杭州市佛教协会副会长、灵顺寺住持印旭法师圆寂,享年50岁

澎湃新闻记者从印旭法师治丧委员会方面获悉,浙江省佛教协会理事、杭州市佛教协会副会长、杭州北高峰灵...

03-28 10:02:29

世界观热点:羊肚菌撑开“致富伞”

华声在线3月27日讯(通讯员葛倩全媒体记者彭雅惠奉永成)春分过后,宁远县九嶷山瑶族乡西湾村羊肚菌种植基...

03-28 09:12:47

全球快播:浙商中拓03月27日获深股通增持28.94万股

03月27日,浙商中拓获深股通增持28 94万股,最新持股量为80 89万股,占公司A股总股本的0 12%。

03-28 07:41:23

【速看料】无人机板块3月27日跌0.66%,思特威领跌,主力资金净流出9.04亿元

3月27日无人机板块较上一交易日下跌0 66%,思特威领跌。当日上证指数报收于3251 4,下跌0 44%。深证...

03-28 04:43:09

“新运河”通航倒计时,杭州离“超级枢纽”更近了_百事通

“新运河”通航倒计时,杭州离“超级枢纽”更近了

03-28 00:15:49

两部门:继续实施物流企业大宗商品仓储设施用地税收优惠政策 环球微头条

中新经纬3月27日电财政部网站消息,近日,财政部、国家税务总局联合发布《关于继续实施物流企业大宗商品...

03-27 21:43:07

当前聚焦:便民春风优服务 出口退税暖人心

中国青年网齐齐哈尔3月27日电(记者张心觉)为进一步推进“便民办税春风行动”,不断提升纳税人缴费人满...

03-27 20:06:09

大象脚印图片简笔画(大象脚印)

1、大象的脚印就像一个个木桩砸出的圆坑。2、它们主要外部特征为柔韧而肌肉发达的长鼻和扇大的耳朵,具...

03-27 18:42:16

大宗交易:祥源文旅成交760万元,折价3.06%(03-27) 报道

2023年3月27日,祥源文旅发生1笔大宗交易,总成交100万股,成交金额760万元,成交价7 60元,折价3 06%。

03-27 17:05:24

传吉利旗下远程汽车赴美IPO前将再融资 环球通讯

传吉利旗下远程汽车赴美IPO前将再融资

03-27 16:08:50

金煌作品 时光未来,现代主义的极致演绎_环球微速讯

清新自然的城市精神现代主义的极致演绎01客厅Livingroom这是一套300平米的现代风格别墅装修案例,整体空...

03-27 15:05:48

wPS如何打斜箭头 环球快讯

1、打开WPS软件,新建空白文档,找到插入,单击一下,再找到“形状”,单击一下。2、单击“形状”后,就...

03-27 13:16:08

河狸家

1、河狸家创立于2014年。2、为用户提供美甲、美睫、美容、理疗、健身、美体、美发、化妆造型等“泛美业...

03-27 12:03:14

天天快看:金雷股份3月27日盘中涨幅达5%

以下是金雷股份在北京时间3月27日10:54分盘口异动快照:3月27日,金雷股份盘中涨幅达5%,截至10点54分,...

03-27 10:54:31

兴业银行南宁分行普惠金融出实招 线上“兴优贷”助企纾困 焦点要闻

“兴业银行推出的线上‘兴优贷’产品真好,给我名下企业放款1000万元,及时补充企业现金流。感谢兴业银...

03-27 09:41:14

现代汽车计划年内在美成立空中出行子公司

据财联社报道,现代汽车集团最早将于上半年在美国华盛顿成立专门负责城市空中出行(UAM)项目的子公司。...

03-27 08:17:29

今日量比是什么意思换手率多少才合适_量比是什么意思_当前关注

1、(1)量比是衡量相对成交量的指标。2、它是指股市开市后平均每分钟的成交量与过去5个交易日平均每分钟...

03-27 05:52:38

贵州省黔东南苗族侗族自治州黄平县2023-03-26 21:13发布雷电黄色预警 当前关注

一、贵州省黔东南苗族侗族自治州黄平县天气预报1、黄平县气象台2023年3月26日21时13分发布雷电黄色预警...

03-27 01:01:25

气温“狂飙”!洛阳最高气温将升至25℃

这个双休日,您和家人出门赏花了吗?好消息是,阳光将持续在线,一路向暖,洛阳下周最高气温将达到25℃...

03-26 21:30:29

秦巴盆地美汉中|天天观天下

【大美中国】每个人心中都有属于自己的桃花源。北依秦岭,南屏巴山,三千里汉江源头的汉中,奇山秀水与...

03-26 19:05:49

从百草园到三味书屋好句批注_从百草园到三味书屋好句 今日快讯

1、1 不必说碧绿的菜畦,光滑的石井栏,高大的皂荚树,紫红的桑葚;也不必说鸣蝉在树叶里长吟,肥胖的...

03-26 17:12:12

耗子尾汁是什么梗_网络语耗子尾汁是什么意思_新资讯

欢迎观看本篇文章,小勉来为大家解答以上问题。耗子尾汁是什么梗,网络语耗子尾汁是什么意思很多人还不...

03-26 14:59:16

如何注销QQ秀

大家好,下面为大家介绍如何注销QQ秀功能。通过检索工具搜索注销QQ秀,选择官方网页点击进入。在官方页...

03-26 13:25:25

整改“一键打新”!多家券商已开始行动!

早在约一年前,当时新股频频破发,券商中国微信公众号刊发了多篇报道,建议对“一键打新”以及新股中签...

03-26 12:05:48

美国密西西比州受龙卷风影响地区进入紧急状态 全球速读

据美国有线电视新闻网当地时间3月25日报道,美国密西西比州州长泰特·里夫斯宣布该州所有受龙卷风影响的...

03-26 10:03:15

怂怂txt下载 世界最资讯

1、链接:提取码:afhz小说名称:怂怂[快穿]作者:扶苏与柳叶类型:穿越连载状态:已完结字数:769962字简介:

03-26 07:10:25

乌克兰与中国时差几个小时 乌克兰和中国时差多少个小时 全球快看

导语:大家都知道,有些国家与国家之间是有时差的,你在这个国家的时候是深夜,去到另个国家就是中午了...

03-26 06:12:20

今日无言以对歌词王以太(无言以对 歌词)

无言以对歌词王以太,无言以对歌词很多人还不知道,现在让我们一起来看看吧!1、窗外天亮了房里还是有点...

03-26 02:01:48

每日速看!以赛提技培育数字产业工人“第一方阵”
西安雁塔保租房附近学校盘点(幼儿园+初中+小学)
盗窃罪量刑标准是什么?抢劫罪与盗窃罪数额的区别是什么?
任天堂 Wii 模拟器 Dolphin 将于今年第 2 季度登陆 Steam 平台|天天消息
【贯彻二十大精神 延安在行动】延安:科学春耕春管 打好丰收基础
一刻钟便民生活圈建设加快推进 一刻钟 “圈”出美好生活-世界快播
高架上出了事故,才知驾照已被扣13分
三叶草生物-B(02197.HK)发布年度业绩,股东应占亏损24.52亿元 同比收窄59.25%
杀疯了!1TB M.2固态硬盘低至288元
可持续发展的基本原则是_可持续发展的基本原则主要包括_ 环球精选
厨电2023:一面混战,一面集中|当前热文
“我可能是最后一次登长城了”,一封从青岛寄到绍兴公安局的信,只因为一个约定_世界热文
河北保定市联西教育集团:融汇优质资源探路创新人才培养 重点聚焦
【A-SOUL制作委员会的双周QA 03.28】|当前热文
工信部:引导和支持民营企业、平台企业参与国家重大科技创新 打造世界级数字产业集群
连衣裙用英语怎么写_连衣裙的英文是什么
天天新消息丨想看客观评价的进来
2023贵州“粤港澳大湾区桥头堡”系列赛(黎平站)暨2023“跑乡村·助振兴”中国传统村落(黔东南)健身休闲大会举行
焦点热文:爱丽丝镜中世界奇遇记英文版_爱丽丝镜中世界奇遇记
世界速看:【Spring源码】- 05 扩展点之BeanPostProcessor
欠钱怎么构成诈骗案
【天天新要闻】杭州市佛教协会副会长、灵顺寺住持印旭法师圆寂,享年50岁
世界观热点:羊肚菌撑开“致富伞”
全球快播:浙商中拓03月27日获深股通增持28.94万股
【速看料】无人机板块3月27日跌0.66%,思特威领跌,主力资金净流出9.04亿元
“新运河”通航倒计时,杭州离“超级枢纽”更近了_百事通
两部门:继续实施物流企业大宗商品仓储设施用地税收优惠政策 环球微头条
当前聚焦:便民春风优服务 出口退税暖人心
大象脚印图片简笔画(大象脚印)
大宗交易:祥源文旅成交760万元,折价3.06%(03-27) 报道
传吉利旗下远程汽车赴美IPO前将再融资 环球通讯
金煌作品 时光未来,现代主义的极致演绎_环球微速讯
wPS如何打斜箭头 环球快讯
河狸家
天天快看:金雷股份3月27日盘中涨幅达5%
兴业银行南宁分行普惠金融出实招 线上“兴优贷”助企纾困 焦点要闻
现代汽车计划年内在美成立空中出行子公司
今日量比是什么意思换手率多少才合适_量比是什么意思_当前关注
贵州省黔东南苗族侗族自治州黄平县2023-03-26 21:13发布雷电黄色预警 当前关注
气温“狂飙”!洛阳最高气温将升至25℃
秦巴盆地美汉中|天天观天下
从百草园到三味书屋好句批注_从百草园到三味书屋好句 今日快讯
耗子尾汁是什么梗_网络语耗子尾汁是什么意思_新资讯
如何注销QQ秀
整改“一键打新”!多家券商已开始行动!
美国密西西比州受龙卷风影响地区进入紧急状态 全球速读
怂怂txt下载 世界最资讯
乌克兰与中国时差几个小时 乌克兰和中国时差多少个小时 全球快看
今日无言以对歌词王以太(无言以对 歌词)
门头沟这处棚改定向安置房即将精装修!另一地块完工待交竣!
X 广告
资讯
X 广告

Copyright ©  2015-2022 北方畜牧网版权所有  备案号:京ICP备2021034106号-50   联系邮箱: 55 16 53 8@qq.com