当前位置: 首页 >  资讯  > 正文

世界要闻:【Netty源码分析】03 客户端接入流程

  • 2023-03-28 22:17:11 来源:腾讯云

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服务端启动完成,这时候客户端连接就可以接入进来了,下面我们就来分析下客户端连接接入的流程。

前2个月营收利润双降 汽车制造业待回温

3月27日,中国汽车工业协会整理的国家统计局数据显示,今年前2个月,汽车制造业营收12847 3亿元,同比...

克莱斯勒在美召回超5万辆Jeep牧马人|天天热门

3月28日,据美国国家公路交通安全管理局披露,克莱斯勒召回部分2020-2023款Jeep牧马人车型,共计5 8万...

2月汽车行业OTA共更新 284 项功能

3月28日,中国汽车流通协会汽车市场研究分会(乘用车市场信息联席会)联合广州威尔森信息科技有限公司发...

关注:第二座欧洲工厂陷入停滞?宁德时代回应:假消息

3月28日,有消息称,今年2月,宁德时代计划投资73 4亿欧元的第二座欧洲工厂,因遭当地居民反对陷入停滞...

北京草莓音乐节定档五一假期_当前信息

据摩登天空官方微博,2023北京草莓音乐节即将回归,定档五一假期,将于4月29日-5月1日与乐迷见面,更多...

成语塞翁失马焉知非福是什么意思_塞翁失马焉知非福是什么意思-世界滚动

1、塞翁失马,焉知非福的意思是:比喻虽然一时受到损失,也许反而因此能得到好处。2、形容人的心态,一...

成都地铁18号线快线时刻表(2023年最新)_焦点热文

成都地铁18号线快线时刻表后续,快线时刻表仍会根据客流变化进行调整,敬请关注,一切以官方信息为准。...

【全球报资讯】幽灵妓女回忆录

1、◎译名恐怖大师系列:印记 鬼伎回忆录◎片名MastersOfHorrorImprint◎年代2

今年GDC游戏风向标,鹅厂技术大牛都支了哪些招?

一直以来,很多人都觉得,游戏只是一种娱乐方式,但却忽视了游戏拥有许多实实在在的硬核技术。

港股异动 | 鞍钢股份(00347)升5% 富达再度增持H股 机构建议关注鞍钢系等优质钢铁央国企 世界微资讯

鞍钢股份(00347)相对活跃,尾盘升约5%。22日,富达再度进场增持鞍钢股份H股,持仓占比由5 22%升至6 35...

民生二卡信报怎么显示?民生京东PLUS联名卡额度多少?

农行信用卡积分当钱花想要用农行信用卡积分抵现,需要在手机上下载一个本来生活APP,注册账号进行登录,...

智能新能源卡车造车新势力DeepWay完成7.7亿元A+轮股权融资:热推荐

3月28日,智能新能源卡车造车新势力公司DeepWay宣布,完成7 7亿元A+轮股权融资,目前DeepWay已累积融资超过12亿元。

民生信用卡5000直提5万有啥技巧?建行信用卡提额到5万需要多久?

民生信用卡5000直提5万民生信用卡额度是比较容易提的,不过从5000直提到5万,额度翻了10倍,虽说是可以...

信用卡没还会影响花呗使用吗?信用卡如何使用提额比较快?

信用卡没还会影响花呗使用吗?信用卡没还不一定会影响花呗使用的,毕竟花呗开通后不会去查征信的,有额度...

征信信用卡审批有影响吗?花呗被冻结原因有哪些?

征信信用卡审批有影响征信上的信用卡审批记录,属于硬查询记录,和贷款审批、担保资格审查一样,都会影...

信用卡冻结积分可以兑换礼品吗?广发分期冲账是什么意思?

信用卡冻结积分可以兑换礼品吗?其实,对信用卡冻结积分是否能用,每个银行都没有明确的答复,但是根据大...

信用卡逾期了还能延期还款吗?超期还款天数怎么计算?

超期还款天数怎么计算?超期还款天数是不包括还款日当天,而是从第二天开始计算的。打个比方,招行信用卡...

中铁大连地铁五号线公司回应“列车车门自动打开”:系机械故障

(记者杨毅)针对28日大连地铁五号线“列车车门自动打开”一事,中铁大连地铁五号线公司发布消息称,系单...

怎么点外卖更省钱?哪个银行信用卡审批通过率高?

怎么点外卖更省钱很多朋友经常在美团、饿了么点外卖,虽说开通会员可以领优惠券,但是有数量限制,不能...

今日热搜:巨头AI混战背后,“卖水的”赚麻了

继文心一言发布、微软全线接入GPT-4后,大佬们又有新动作了。3月21日晚上11点,GTC2023开幕,英伟达CEO...

首发基金好还是老基金好?混合基金怎么选?

混合基金有哪些优点混合基金是指同时投资于股票、债券和货币市场等工具,没有明确的投资方向的基金。债...

IOPV有什么用?基金定投赚钱的诀窍是什么?

IOPV有什么用简单来说,ETF引入IOPV指标,是较为准确的反映了ETF份额中的实时净值,也提高了交易的透明...

REITs基金靠谱吗?基金的换手率对基金有什么影响?

基金的换手率对基金有什么影响基金的换手率是我们在了解一只基金的时候比较重要的参考指标,所谓换手率...

基金放几年合适?基金放的越久越好吗?

基金放几年合适基金放几年,会不会赚钱,其实可以根据基金的类型来考虑:如果是货币基金的话,其实随便...

为什么大家都说基金定投是“懒人理财法”呢?新手小白如何挑选基金?

为什么大家都说基金定投是懒人理财法呢?因为基金定投有以下的优点:1、基金定投相当于每个月强迫储蓄,...

行业指数基金怎么选?买基金选多大规模比较好?

行业指数基金怎么选我们做基金投资,如果是入门级别的选手的话,我们建议可以直接从沪深300和中证500指...

混合基金与股票基金哪个风险大?基金如何实现翻倍呢?

混合基金与股票基金哪个风险大混合型基金又称混合基金,是指以股票、债券等为投资对象的基金。混合型基...

次新股的限售解禁会暴跌吗?股票大小非减持对股价走势影响多大?

股票怎么有效控制回撤设置止盈止损止盈止损在短线操作中尤为重要,稍不注意账户就会出现大幅回撤,我们...

FAENZA 法恩莎Tyla泰拉系列喜提住宅部品工业设计最高荣誉——红鼎·综合TOP10

3月27日,FAENZA法恩莎受邀参与2021-2022住宅产业年会暨第六届CBDA住宅产业(红鼎)创新大赛发布仪式,...

债转股和可转债是一回事吗?填权股如何操作?

填权股如何操作如果是高价股除权,那么不要在除权后马上买进,因为这样的股票往往有高估的风险。如果是...

如何用量比看成交量变化?股票填权还是贴权怎么看?

量比怎么计算与换手率、委比、委差等百分率指标不同的是,量比通常是一个倍数,倍数的大小反映短期内成...

书香满校园 西安经开区各学校“书市”活动精彩纷呈

为进一步激发学生的阅读兴趣,提升学生阅读素养和人文素养,近日,西安经开区多所学校开展了精彩的“书...

开盘集合竞价能看出主力意图吗?量比越大越好吗?

仙人指路形态买卖点与仓位控制当判断股票出现仙人指路形态后,买点有三种,卖点无法预判只能根据盘面信...

主力出货的信号有哪些?股票仙人指路形态如何确定?

主力出货的信号散户想要在主力出货之前逃顶,就必须提前观察到主力出货的信号,一旦主力有所动作就可以...

重大资产重组是利好还是利空?散户为什么不喜欢买白马股?

重大资产重组是利好还是利空公司发生重大资产重组,需公告停牌并报请证监会和交易所批准。如果被收购方...

散户怎么寻找黄金坑形态的买点?常见资产重组方式有哪些?

散户怎么寻找黄金坑形态的买点?1 激进的买点是大阴线破位下跌时带长下影线,可以预判买入少量仓位。2...

如何筛选黄金坑股票?市盈率选股的注意事项有哪些?

市盈率种类市盈率是指股票的市场价格与每股盈利的比值,又叫本益比。它反映的是股东买入股票的成本与持...

上市公司回购的股票如何处理?新手如何建立自己的股票池?

回购的股票如何处理1 直接注销,以减少市场流通股本的数量,这样可以提高每股盈利,从而是市盈率降低...

融资融券的原理是什么?股票加杠杆有风险吗?

融资融券的原理是什么两融业务的原理说白了,就是有些投资者觉得自己资金太少但又想多赚钱,刚好证券公...

股票新手怎样快速入门?配资炒股风险大不大?

配资炒股风险大不大与不配资的人相比较,风险肯定是变大了,但同时对于需要资金来扩大投资以获取更高收...

刚刚,河南上榜!| 地球知识局-今日快看

地球知识局微信公众号:地球知识局据说地球人民都关注分享我局了(⊙v⊙)二里头遗址新发现作者:赵海涛制...

我国人工智能学科主要奠基人涂序彦逝世,享年 88 岁

IT之家3月28日消息,据北京科技大学消息,我国人工智能领域著名科学家、人工智能学科的主要奠基人、中国...

26国驻华使节“打卡”赛力斯汽车

外交部近日组织来自欧洲、非洲、亚洲的26个国家和地区的驻华使节代表团赴重庆参访,智能制造第一站便走...

℃摄氏度符号怎么打?如何对自己的二手手机进行估价?

℃摄氏度符号怎么打01利用搜狗输入法打摄氏度符号02点击最右边的工具箱按钮-表情符号-符号大全。03出现...

剁手是什么意思表情包_剁手是什么意思

1、剁手是指网上购物,不知不觉间花费大量金钱,回头一看账单懊恼不已。2、自嘲要剁手。本文就为大家分...

如何批量修改图片尺寸?MATLAB绘制函数图像入门看这里

如何批量修改图片尺寸?01直切主题,软件是免安装的绿色小工具,直接双击运行exe程序就能使用了。如下图...

上古卷轴5原版捏脸攻略来了!如何设置雷蛇外设驱动?

上古卷轴5原版捏脸攻略01选择了个预设脸,然后选了个还可以的眼睛和一个嘴巴,鼻子,然后随便捏了一下。...

怎样快速修改图片上的文字和数字?ps怎么抠图放到另一张图片上?

怎样快速修改图片上的文字和数字01首先在我们的电脑桌面上找到美图秀秀并点击它,如下图所示。02然后点...

如何用WiFi万能钥匙使电脑连上WiFi?手机怎么共享WiFi给台式电脑?

如何用WiFi万能钥匙使电脑连上WiFi01若自己的手机还未能连上WiFi,那么可以下载一个WiFi万能钥匙,打开...

精彩放送

网上抢票攻略来了!怎么强制加qq好友?

比亚迪海洋旗舰深度试驾体验日北京站收官:全球热头条

"18华润置地MTN002B4"将于4月4日兑付 债券余额为35亿元

环球播报:马斯克又嘲讽比尔盖茨:到今天,他对AI的理解依然有限

广西举办第11届节地生态安葬活动 2356名逝者骨灰与花草为伴

新能源充电器插头发热正常吗?纯电动汽车怎么开省电?

10万以内的新能源电动车有哪些?新能源汽车北方冬天可以用吗?

雨后贪鲜吃野蘑菇? 每日关注

环球时讯:理想汽车组织动刀:OKR升级为PBC,绩效考核周期延长至半年

新能源新车磨合期注意事项有哪些?新能源车年检新规2023年新规定看这里

增程式汽车哪款比较好?增程式汽车十大缺点看这里

紫藤花开如瀑!那一抹浪漫紫梦幻了南宁的春天:全球今亮点

广西人吃“ong菜”冲上热搜!今年的空心菜市场售价如何?

“老表”会师!广西仔连续两年“轮庄”CBA星锐赛MVP

广西举办第十一届节地生态安葬活动 2356名逝者骨灰与鲜花为伴-环球微动态

特别聚焦|大藤峡工程右岸第三台机组正式投产发电

日系宝马是什么车?国产gti有没有差速器?

奇瑞a3发动机号在哪个位置?排量最小的车是什么车?

个人房屋转租租合同怎么写?个人房屋转租租合同范本一览-焦点热讯

《我的思念是圆的》 教案该如何设计?《我的思念是圆的》 教案设计汇总 世界实时

村民养殖黄沙鳖能发家致富吗?相关信息快来了解下吧!

世界十大火山有哪些?世界十大火排名介绍

八年级上册历史教学计划有哪些?八年级上册历史教学计划详情介绍

胡雪岩经典名言有哪些?胡雪岩经典名言值得收藏!

环球今热点:初二新学期的学习计划怎么写?初二新学期的学习计划范文一览

雅思阅读的关键词都有什么?雅思阅读中九类关键词详解

搞笑的电视广告词都有哪些?搞笑的电视广告词推荐

关于俄罗斯的地理知识 你了解多少呢?-世界时讯

每日精选:心中的美景作文精选3篇 详情内容快来看看吧!

【独家】劳动法加班小时工资怎么计算?劳动法加班小时工资计算方法是什么?

北方的雪美文欣赏 建议收藏_快播

精细化管理方案如何写?精细化管理方案(通用9篇)

当前速递!小学教师的年度工作怎么总结?小学教师的年度工作总结3篇

美丽的城市作文(精选20篇) 感兴趣的小伙伴快来看看吧!

生活常见的英语词汇有哪些?生活常见的英语词汇大全

读后感怎么写?《城南旧事》读后感范文汇总

要闻:《心理学与生活》这本书你读过吗?心理学与生活读后感(精选10篇)

煤矿常见职业病有什么危害?该如何防治?

阅兵车是什么车型?本田商务车叫什么名字?

12123免扣分政策是真的吗?阅兵车辆为什么有一辆是空的?

速腾后悬挂断是哪一批车?汽车下乡车型有哪些?

刹车失灵可以直接熄火吗?磨合期油耗与正常油耗差多少?

安全气囊灯亮了还可以继续开吗?江铃驭胜S350发动机是哪产的?

烛光小学的刘老师,好棒! 全球今日讯

视点!外媒:马斯克的脑机接口公司正寻找人体试验合作伙伴

重实效 强实干 抓落实丨百色首趟铝产品集装箱直达班列驶向广东:报资讯

这个杀手不太冷台词哪些比较经典?这个杀手不太冷结局寓意看这里

夏天的文案唯美短句来了!期待夏天的文案温柔都在这儿

写夏至的最佳古诗你知道多少?含惊蛰诗句都在这儿

初三化学不好怎么补救?如何学好物理的方法和技巧高中看这里

联系我们:55 16 53 8@qq.com
关于我们| 联系方式| 版权声明| 供稿服务| 友情链接

华讯网 版权所有,未经书面授权禁止使用

京ICP备2021034106号-10 营业执照公示信息

Copyright©2008-2020 By www.saibeinews.com All Rights Reserved