Netty实战(二)

一、环境准备

Netty需要的运行环境很简单,只有2个。

  • JDK 1.8+
  • Apache Maven 3.3.9+

二、Netty 客户端/服务器概览

在这里插入图片描述
如图,展示了一个我们将要编写的 Echo 客户端和服务器应用程序。该图展示是多个客户端同时连接到一台服务器。所能够支持的客户端数量,在理论上,仅受限于系统的可用资源(以及所使用的 JDK 版本可能会施加的限制)。

Echo 客户端和服务器之间的交互是非常简单的;在客户端建立一个连接之后,它会向服务器发送一个或多个消息,反过来服务器又会将每个消息回送给客户端。虽然它本身看起来好像用处不大,但它充分地体现了客户端/服务器系统中典型的请求-响应交互模式

三、编写 Echo 服务器

所有的 Netty 服务器都需要以下两部分。

  • 至少一个 ChannelHandler—该组件实现了服务器对从客户端接收的数据的处理,即它的业务逻辑。
  • 引导—这是配置服务器的启动代码。至少,它会将服务器绑定到它要监听连接请求的端口上。

3.1 ChannelHandler 和业务逻辑

上一篇博文我们介绍了 Future 和回调,并且阐述了它们在事件驱动设计中的应用。我们还讨论了 ChannelHandler,它是一个接口族的父接口,它的实现负责接收并响应事件通知。

在 Netty 应用程序中,所有的数据处理逻辑都包含在这些核心抽象的实现中。因为你的 Echo 服务器会响应传入的消息,所以它需要实现ChannelInboundHandler 接口,用来定义响应入站事件的方法。简单的应用程序只需要用到少量的这些方法,所以继承 ChannelInboundHandlerAdapter 类也就足够了,它提供了ChannelInboundHandler 的默认实现。

我们将要用到的方法是:

  • channelRead() :对于每个传入的消息都要调用;
  • channelReadComplete() : 通知ChannelInboundHandler最后一次对channelRead()的调用是当前批量读取中的最后一条消息;
  • exceptionCaught() :在读取操作期间,有异常抛出时会调用。

该 Echo 服务器的 ChannelHandler 实现是 EchoServerHandler,如代码:

package com.example.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import io.netty.util.CharsetUtil;

/**
 * @author lhd
 * @date 2023/05/16 15:05
 * @notes Netty Echo服务端简单逻辑
 */

//表示channel可以并多个实例共享,它是线程安全的
@ChannelHandler.Sharable
public class EchoServerHandler extends ChannelInboundHandlerAdapter {

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        ByteBuf in = (ByteBuf) msg;
        //将消息打印到控制台
        System.out.println("Server received: " + in.toString(CharsetUtil.UTF_8));
        //将收到的消息写给发送者,而不冲刷出站消息
        ctx.write(in);
    }

    @Override
    public void channelReadComplete(ChannelHandlerContext ctx) {
        //将未决消息冲刷到远程节点,并且关闭该 Channe
        ctx.writeAndFlush(Unpooled.EMPTY_BUFFER)
                .addListener(ChannelFutureListener.CLOSE);
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        //打印异常堆栈跟踪
        cause.printStackTrace();
        //关闭该channel
        ctx.close();
    }
}

ChannelInboundHandlerAdapter 有一个直观的 API,并且它的每个方法都可以被重写以挂钩到事件生命周期的恰当点上。

因为需要处理所有接收到的数据,所以我们重写了 channelRead() 方法。在这个服务器应用程序中,我们将数据简单地回送给了远程节点。

重写 exceptionCaught() 方法允许我们对 Throwable 的任何子类型做出反应,在这里你记录了异常并关闭了连接。

虽然一个更加完善的应用程序也许会尝试从异常中恢复,但在这个场景下,只是通过简单地关闭连接来通知远程节点发生了错误。

ps:如果不捕获异常,会发生什么呢?

每个 Channel 都拥有一个与之相关联的 ChannelPipeline,其持有一个 ChannelHandler 的实例链。在默认的情况下,ChannelHandler 会把对它的方法的调用转发给链中的下一个 ChannelHandler。因此,如果 exceptionCaught()方法没有被该链中的某处实现,那么所接收的异常将会被传递到 ChannelPipeline 的尾端并被记录。为此,你的应用程序应该提供至少有一个实现exceptionCaught()方法的 ChannelHandler。

除了 ChannelInboundHandlerAdapter 之外,还有很多需要学习ChannelHandler的子类型和实现。这些之后会一一说明,目前,我们只关注:

  • 针对不同类型的事件来调用 ChannelHandler;
  • 应用程序通过实现或者扩展 ChannelHandler 来挂钩到事件的生命周期,并且提供自定义的应用程序逻辑;
  • 在架构上,ChannelHandler 有助于保持业务逻辑与网络处理代码的分离。这简化了开发过程,因为代码必须不断地演化以响应不断变化的需求。

3.2 引导服务器

下面我们准备开始构建服务器。构建服务器涉及到两个内容:

  • 绑定到服务器将在其上监听并接受传入连接请求的端口;
  • 配置 Channel,以将有关的入站消息通知给 EchoServerHandler 实例。
package com.example.netty;

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

import java.net.InetSocketAddress;

/**
 * @author lhd
 * @date 2023/05/16 15:21
 * @notes Netty引导服务器
 */
public class EchoServer {

    public static void main(String[] args) throws Exception {
        //调用服务器的 start()方法
        new EchoServer().start();
    }

    public void start() throws Exception {
        final EchoServerHandler serverHandler = new EchoServerHandler();
        //创建EventLoopGroup
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //创建ServerBootstra
            ServerBootstrap b = new ServerBootstrap();
            //指定服务器监视端口
             int port = 8080;
            b.group(group)
                    //指定所使用的 NIO 传输 Channel
                    //因为我们正在使用的是 NIO 传输,所以你指定了 NioEventLoopGroup 来接受和处理新的连接,
                    // 并且将 Channel 的类型指定为 NioServerSocketChannel 。
                    .channel(NioServerSocketChannel.class)
                    //使用指定的端口设置套接字地址
                    //将本地地址设置为一个具有选定端口的 InetSocketAddress 。服务器将绑定到这个地址以监听新的连接请求
                    .localAddress(new InetSocketAddress(port))
                    //添加一个EchoServerHandler 到子Channel的 ChannelPipeline
                    //这里使用了一个特殊的类——ChannelInitializer。这是关键。
                    // 当一个新的连接被接受时,一个新的子 Channel 将会被创建,而 ChannelInitializer 将会把一个你的
                    //EchoServerHandler 的实例添加到该 Channel 的 ChannelPipeline 中。正如我们之前所解释的,
                    // 这个 ChannelHandler 将会收到有关入站消息的通知。
                    .childHandler(new ChannelInitializer<SocketChannel>(){
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            //EchoServerHandler 被标注为 @Shareable,所以我们可以总是使用同样的实例
                            //实际上所有客户端都是使用的同一个EchoServerHandler
                            ch.pipeline().addLast(serverHandler);
                        }
                    });
            //异步地绑定服务器,调用 sync()方法阻塞等待直到绑定完成
            //sync()方法的调用将导致当前 Thread阻塞,一直到绑定操作完成为止
            ChannelFuture f = b.bind().sync();
            //获取 Channel 的CloseFuture,并且阻塞当前线
            //该应用程序将会阻塞等待直到服务器的 Channel关闭(因为你在 Channel 的 CloseFuture 上调用了 sync()方法)
            f.channel().closeFuture().sync();
        } finally {
            //关闭 EventLoopGroup,释放所有的资源,包括所有被创建的线程
            group.shutdownGracefully().sync();
        }
    }
}

我们总结一下服务器实现中的重要步骤。下面这些是服务器的主要代码组件:

  • EchoServerHandler 实现了业务逻辑;
  • main()方法引导了服务器;
    引导过程中所需要的步骤如下:
    • 创建一个 ServerBootstrap 的实例以引导和绑定服务器;
    • 创建并分配一个 NioEventLoopGroup 实例以进行事件的处理,如接受新连接以及读/写数据;
    • 指定服务器绑定的本地的 InetSocketAddress;
    • 使用一个 EchoServerHandler 的实例初始化每一个新的 Channel;
    • 调用 ServerBootstrap.bind()方法以绑定服务器。

到此我们的引导服务器已经完成。

四、编写 Echo 客户端

Echo 客户端将会:
(1)连接到服务器;
(2)发送一个或者多个消息;
(3)对于每个消息,等待并接收从服务器发回的相同的消息;
(4)关闭连接。
编写客户端所涉及的两个主要代码部分也是业务逻辑和引导,和你在服务器中看到的一样。

4.1 通过 ChannelHandler 实现客户端逻辑

如同服务器,客户端将拥有一个用来处理数据的 ChannelInboundHandler。在这个场景下,我们将扩展 SimpleChannelInboundHandler 类以处理所有必须的任务。这要求重写下面的方法:

  • channelActive() : 在到服务器的连接已经建立之后将被调用;
  • channelRead0() : 当从服务器接收到一条消息时被调用;
  • exceptionCaught() :在处理过程中引发异常时被调用。

具体代码可以参考如下:

package com.example.netty;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.util.CharsetUtil;

/**
 * @author lhd
 * @date 2023/05/16 15:45
 * @notes Netty 简单的客户端逻辑
 */

//标记该类的实例可以被多个 Channel 共享
@ChannelHandler.Sharable
public class EchoClientHandler extends SimpleChannelInboundHandler<ByteBuf> {

    //当被通知 Channel是活跃的时候,发送一条消息
    @Override
    public void channelActive(ChannelHandlerContext ctx) {
        ctx.writeAndFlush(Unpooled.copiedBuffer("Netty rocks!", CharsetUtil.UTF_8));
    }

    //记录已接收消息的转储
    @Override
    public void channelRead0(ChannelHandlerContext ctx, ByteBuf in) {
        System.out.println("Client received: " + in.toString(CharsetUtil.UTF_8));
    }

    //在发生异常时,记录错误并关闭Channel
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        cause.printStackTrace();
        ctx.close();
    }
}

首先,我们重写了 channelActive() 方法,其将在一个连接建立时被调用。这确保了数据将会被尽可能快地写入服务器,其在这个场景下是一个编码了字符串"Netty rocks!"的字节缓冲区。

接下来,我们重写了 channelRead0() 方法。每当接收数据时,都会调用这个方法。由服务器发送的消息可能会被分块接收。也就是说,如果服务器发送了 5 字节,那么不能保证这 5 字节会被一次性接收。即使是对于这么少量的数据,channelRead0()方法也可能会被调用两次,第一次使用一个持有 3 字节的 ByteBuf(Netty 的字节容器),第二次使用一个持有 2 字节的 ByteBuf。作为一个面向流的协议,TCP 保证了字节数组将会按照服务器发送它们的顺序被接收。

ps:所以channelRead0()的调用次数不一定等于服务器发布消息的次数

重写的第三个方法是 exceptionCaught()。如同在 EchoServerHandler(3.1中的代码示例)中所示,记录 Throwable,关闭 Channel,在这个场景下,终止到服务器的连接。

ps:为什么客户端继承SimpleChannelInboundHandler 而不是ChannelInboundHandler?

在客户端,当 channelRead0()方法完成时,我们已经有了传入消息,并且已经处理完它了。当该方法返回时,SimpleChannelInboundHandler 负责释放指向保存该消息的 ByteBuf 的内存引用。

在 EchoServerHandler 中,我们仍然需要将传入消息回送给发送者,而 write()操作是异步的,直到 channelRead()方法返回后可能仍然没有完成。为此,EchoServerHandler扩展了 ChannelInboundHandlerAdapter,其在这个时间点上不会释放消息。消息在 EchoServerHandler 的 channelReadComplete()方法中,当 writeAndFlush()方法被调用时被释放。

4.2 引导客户端

引导客户端类似于引导服务器,不同的是,客户端是使用主机和端口参数来连接远程地址,也就是这里的 Echo 服务器的地址,而不是绑定到一个一直被监听的端口。

package com.example.netty;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;

import java.net.InetSocketAddress;

/**
 * @author lhd
 * @date 2023/05/16 15:59
 * @notes 引导客户端
 */
public class EchoClient {
  
    public void start() throws Exception {
        //指定 EventLoopGroup 以处理客户端事件;需要适用于 NIO 的实现
        EventLoopGroup group = new NioEventLoopGroup();
        try {
            //创建 Bootstrap
            Bootstrap b = new Bootstrap();
            b.group(group)
                    //适用于 NIO 传输的 Channel 类型
                    .channel(NioSocketChannel.class)
                    //设置服务器的InetSocketAddress
                    .remoteAddress(new InetSocketAddress("127.0.0.1", 8080))
                    .handler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        public void initChannel(SocketChannel ch) throws Exception {
                            //在创建Channel时,向 ChannelPipeline中添加一个 EchoClientHandler 实例
                            ch.pipeline().addLast(new EchoClientHandler());}
                    });
            //连接到远程节点,阻塞等待直到连接完成
            ChannelFuture f = b.connect().sync();
            //阻塞,直到Channel 关闭
            f.channel().closeFuture().sync();
        } finally {
            //关闭线程池并且释放所有的资源
            group.shutdownGracefully().sync();
        }
    }
 public static void main(String[] args) throws Exception {
        new EchoClient().start();
    }
}

总结一下要点:

  • 为初始化客户端,创建了一个 Bootstrap 实例;
  • 为进行事件处理分配了一个 NioEventLoopGroup 实例,其中事件处理包括创建新的连接以及处理入站和出站数据;
  • 为服务器连接创建了一个 InetSocketAddress 实例;
  • 当连接被建立时,一个 EchoClientHandler 实例会被安装到(该 Channel 的)
    ChannelPipeline 中;
  • 在一切都设置完成后,调用 Bootstrap.connect()方法连接到远程节点;

综上客户端的构建已经完成。

五、构建和运行 Echo 服务器和客户端

将我们上面的代码复制到IDEA中运行,先启动服务端在启动客户端会得到以下预期效果:

服务端控制台打印:
在这里插入图片描述
客户端控制台打印:
在这里插入图片描述
我们关闭服务端后,客户端控制台打印:
在这里插入图片描述
因为服务端关闭,触发了客户端 EchoClientHandler 中的exceptionCaught()方法,打印出了异常堆栈并关闭了连接。

这只是一个简单的应用程序,但是它可以伸缩到支持数千个并发连接——每秒可以比普通的基于套接字的 Java 应用程序处理多得多的消息。

本文转载于网络 如有侵权请联系删除

相关文章

  • ThreadLocal还能更快?

    1FastThreadLocal的引入背景和原理简介既然jdk已经有ThreadLocal,为何netty还要自己造个FastThreadLocal?FastThreadLocal快在哪里?这需要从jdkThreadLocal的本身说起。如下图:在java线程中,每个线程都有一个ThreadLocalMap实例变量(如果不使用ThreadLocal,不会创建这个Map,一个线程第一次访问某个ThreadLocal变量时,才会创建)。该Map是使用线性探测的方式解决hash冲突的问题,如果没有找到空闲的slot,就不断往后尝试,直到找到一个空闲的位置,插入entry,这种方式在经常遇到hash冲突时,影响效率。FastThreadLocal(下文简称ftl)直接使用数组避免了hash冲突的发生,具体做法是:每一个FastThreadLocal实例创建时,分配一个下标index;分配index使用AtomicInteger实现,每个FastThreadLocal都能获取到一个不重复的下标。当调用ftl.get()方法获取值时,直接从数组获取返回,如returnarray[index],如下

  • --Postgresql 建表疏忽导致的数据无法插入,发现奇怪的问题

    此前在其他的数据库并未注意到这点,POSTGRESQL建立字符字段的时候,可以大量使用TEXT的形式来存储字符。建表的时候粗心在建立表后,插入数据一直报错当时没有注意,认为是符号的错误导致的写入数据的问题,修改了半天insert的语句,报错也改变了 最终发现不是insert语句的问题而是建表的时候产生的问题。版本(PGV12.2)注意建表的时候将text写成了test,导致建表后,字段的类型不对。导致后面输入数据错误。altertablelaptopALTERCOLUMNtypeSETDATATYPEtext;在进行插入数据插入成功,这留下一个问题,为什么写错的数据类型还能建立表。尝试将其他的类型写错了,看看能不能建立表再次创建一个表,尝试将类型写错,也是通过的 首先要确认的是这里并没有组合类型的设置和建立,而发现此次问题的也是偶然的。随即查找到底什么原因导致这个问题,或可能的原因是什么随即建立新的数据库,模拟问题没有成功再次创建数据表,发现没有成功的模拟出问题。随即对原数据库进行分析1原有的数据库的默认的schema是test2原有的数据库加装了citext插件随即再次模拟情况失败

  • 【STM32F429】第8章 ThreadX调试方法(串口和RTT两种方式打印任务执行情况)

    论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99514第8章ThreadX调试方法(串口和RTT两种方式打印任务执行情况)本章节为大家介绍ThreadX的调试方法,这里的调试方法主要是教会大家如何获取任务的执行情况,通过获取的任务信息,可以进一步的配置和优化工程,这种方法非常实用,建议初学者必须掌握。8.1初学者重要提示8.1串口或RTT打印调试说明8.2ThreadX实现串口或者RTT打印任务执行情况8.3ThreadX的CPU利用率实现方法8.4总结8.1初学者重要提示。RTT打印相关基础知识可以看此贴:【专题教程第5期】工程调试利器RTT实时数据传输组件,替代串口调试,速度飞快,可以在中断和多任务中随意调用http://www.armbbs.cn/forum.php?mod=viewthread&tid=86177。8.2串口或RTT打印调试说明很多时候我们需要了解任务的执行状态,任务栈的使用情况以及各个任务的CPU使用率。对此,我们这里封装了一个函数。获取了任务执行情况后,可以通过

  • VB来开发打字高手游戏,灵活运用时钟控件【VB学习笔记2020课堂版09】

    简介INTRODUCTION时钟控件+控件数组的典型案例课题9时钟控件的灵活使用授课:刘金玉打字高手小游戏开发:知识要点:1.随机数知识2.timer控件的使用3.窗体启动加载事件form_load4.键盘事件的使用5.ascii码的转换6.相关逻辑:if语句大小判断7.随机颜色的使用实现步骤:1.载入几个控件,用来存储随机产生的字符2.用timer控件来控制字符的下降3.逻辑判断是否打中相应的字符,打中字符后重置随机字符的位置4.记录得分分值软件设计界面: form源代码: VERSION5.00 BeginVB.FormForm1 Caption="打字游戏--byljy" ClientHeight=5955 ClientLeft=120 ClientTop=450 ClientWidth=9135 LinkTopic="Form1" ScaleHeight=5955 ScaleWidth=9135 StartUpPosition=3'窗口缺省 BeginVB.TimerTimer1 Interval=500 Left=960 To

  • 一招鲜,吃遍天,杂故而不精

    今天偶然翻看了这几年自己看过的文章,估计有上千篇了吧,基本上都是和技术相关的,或者与技术扯皮的文章,真的很恐怖[打脸],由于工作中用的不是很多,所以慢慢淡忘了很多,你要是问我知不知道这个技术我可能有所耳闻,或者说出一点自己的理解[打脸]。自从javaweb技术的发展,技术的迭代更新快的让你摸不着头脑,或许你得心应手的jsp也早已被前端优秀的框架代替了,解析xml我们可以使用dom4j,sax,xstream等进行解析,这些由于json的超规模应用也慢慢退出历史舞台,汗颜。然而json技术的出现也随之诞生出了fastjson,gson,jackon等框架技术的出现,简单而实用的特性也使得我这样的码农用的不亦乐乎,感谢各位优秀开源作者对其的贡献。谈到xml这个古老的技术,不得不提一下websevice,它也是rmi远程方法调用的简称的一种,后面又出现了cxf框架,又有新的框架提携我这样的码农了,感恩,感谢。由于http协议是一种应用层协议,简单实用的特性,后面又接触了httpClient技术,restTemplate技术以及feign组件的出现,方法调用这么简单。作为报表导出excel数据

  • Java Review (十二、面向对象----final 修饰符)

    final关键宇可用于修饰类、方法和变量,被它修饰的类、方法和变量不可改变。final变量final成员变量成员变量是随类初始化或对象初始化而初始化的。当类初始化时,系统会为该类的类变量分配内存,并分配默认值;当创建对象时,系统会为该对象的实例变量分配内存,并分配默认值。对于final修饰的成员变量而言,一旦有了初始值,就不能被重新赋值,如果既没有在定义成员变量时指定初始值,也没有在初始化块、构造器中为成员变量指定初始值,那么这些成员变量的值将一直是系统默认分配的0、'\u000'、false或null,这些成员变也就完全失去了存在的意义。因此:Java语法规定final修饰的成员变量必须由程序员显式地指定初始值。归纳起来,final修饰的类变量、实例变量能指定初始值的地方如下:类变量:必须在静态初始化块中指定初始值或声明该类变量时指定初始值,而且只能在两个地方的其中之一指定。实例变量:必须在非静态初始化块、声明该实例变量或构造器中指定初始值,而且只能在三个地方的其中之一指定。final成员变量实例publicclassFinalVariableTest{ //定义

  • 构建深度神经网络实现猫的二分类

    原文博客:Doi技术团队 链接地址:https://blog.doiduoyi.com/authors/1584446358138 初心:记录优秀的Doi技术团队学习经历 目录文章目录目录前言导包初始化网络参数两层网络的初始化L层网络的初始化正向传播模块线性正向传播线性激活正向传播L层模型正向传播计算损失函数反向传播模块线性反向传播线性激活反向传播L层模型反向传播更新模型参数预测正确率两层神经网络模型L层神经网络模型预测自己的图像模型的使用两层模型的使用L层模型的使用预测自己的图像参考资料前言这次使用一个猫的数据集,我们使用深度神经网络来识别这个是猫或者不是猫。 导包这里导入了两个工具类,可以从这里下载,这里包含了这个函数和用到的数据集,其中用到了h5py,如果读者没有安装的话,要先用pip安装这个库,还有以下用到的库也要安装。#coding=utf-8 fromdnn_utils_v2importsigmoid,sigmoid_backward,relu,relu_backward fromlr_utilsimportload_dataset importnumpyasnp impo

  • 移动机器人中的现代控制理论之状态反馈观测与最优控制

    对于稳定的系统,控制的用途使其满足目标期望;对于不稳定的系统,分析是否可以进行配置使其稳定,然后再像稳定系统一样,控制其满足目标期望;最优控制对性能指标提出了更高的要求,除了稳定和与期望目标误差小,还需要满足特定的性能指标。观察下面示例(倒立摆小车,与常见的平衡代步车结构类似):稳定?如何保持摆的稳定性?如何实现?稳定+轨迹?如何设计控制器,在摆稳定的前提下,机器人在空间做规定的曲线运动?提示:(请参考如下两篇博文)https://blog.csdn.net/ZhangRelay/article/details/88200899https://zhangrelay.blog.csdn.net/article/details/51668647全部资料下载链接:http://pan.baidu.com/s/1kV4KT19

  • Linux常用的服务器构建

    Linux常用的服务器构建一、ftp服务器FTP是FileTransferProtocol(文件传输协议)的英文简称,而中文简称为“文传协议”。用于Internet上的控制文件的双向传输。同时,它也是一个应用程序(Application)。基于不同的操作系统有不同的FTP应用程序,而所有这些应用程序都遵守同一种协议以传输文件。在FTP的使用当中,用户经常遇到两个概念:"下载"(Download)和"上传"(Upload)。  "下载"文件就是从远程主机拷贝文件至自己的计算机上;  "上传"文件就是将文件从自己的计算机中拷贝至远程主机上。用Internet语言来说,用户可通过客户机程序向(从)远程主机上传(下载)文件。1.安装vsftpd服务器sudoaptinstallvsftpd  或者  sudoapt-getinstallvsftpd复制2.配置vsftpd.conf文件sudovi/etc/vsftpd.conf复制配置vsftpd.conf文件后,保存退出该文件。接下来进行:写好后,保存并退出。3

  • WIN7网络和共享中心显示未知但可以上网解决方式

    今天在试一个《骑马与砍杀》的游戏相关问题的解决方法时,用了cmd命令中dll相关命令,没想到游戏问题没解决,还多了个“网络和共享中心显示未知”,右下角网络那成了叉号,在网上搜了半天,目前总算解决了一部分(本地连接等暂时还没出来),先将解决了的分享出来。先看效果图:修改前效果图修改前目前修改后目前修改后PS:2013年12月16日更新:今天发现竟然右下角的本地连接等宽度连接自己出来了,一切都恢复正常了,也就是说只要完成之前那些就足够了(即这里提到的)。虽然网络可以正常使用,但这么看着总是有点不舒服。我用的方法是"启动NetworkListService复制"服务,现象及方法如下:现象:网络连接的小图标上多了一个小红叉,但不影响上网,提示了服务NetworkListService没有启动。 解决办法: 打开组件服务-》点开计算机-》我的电脑-》DCOM配置, 找到netprofm点开netprofm的属性(右键-》属性)-》安全-》“启动和激活权限”-》自定义--》编辑, 在启动权限里添加LOCALSERVICE用户,允许本地启动和本地激活,确定就OK了。 具体操作步骤

  • 机器学习 学习笔记(19)神经网络

    神经元模型神经网络是由具有适应性的简单单元组成的广泛并行互连的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应。神经网络中最基本的成分是神经元模型。M-P神经元模型,在这个模型中,神经元接收到来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将于神经元的阈值进行比较,然后通过激活函数处理以产生神经元的输出。理想的激活函数是阶跃函数,但是阶跃函数具有不连续、不光滑等不太好的性质,因此实际常用Sigmoid函数作为激活函数。感知机与多层网络感知机由两层神经元组成,输入层接收外界输入信号后传递给输出层,输出层是M-P神经元,亦称为“阈值逻辑单元”。感知机能很容易地实现逻辑与、或、非运算。感知机只有输出层神经元进行激活函数处理,即只拥有一层功能神经元,其学习能力非常有限,与、或、非问题都是线性可分的。要解决非线性可分问题,需考虑使用多层功能神经元,如异或问题。输入层与输出层之间的神经元被称为隐层或者隐含层,隐含层和输出层神经元都是拥有激活函数的功能神经元。神经网络的学习过程,就是根据训练数据来调整神经元之间的连接权以及每个功能神经

  • centos6.8部署vnc服务

    VNC全称是VirtualNetworkComputing,属于远程控制类软件。其优点是支持跨操作系统的远程图形化控制。 在日常运维工作中,由于服务器常常是放在机房,我们不可能每次需要图形界面操作就跑到机房,因此vnc是一款不错的替代软件。下面记录在centos6环境下安装vnc的操作:(1)查看本机是否已经安装vncserver [root@server~]#rpm-qa|greptigervnc(2)安装vncserver [root@server~]##yum-yinstalltigervnc-server(3)启动并设置vncserver密码 在第一次启动vncserver会提示输入密码,之后就需要使用vncpasswd命令 [root@server~]##vncserver Password: Verify:(4)修改/root/.vnc/xstartup文件 由于我们这里使用的centos系统,安装的是gnome桌面 [root@server~]##sed-i's/twm&/gnome-session&/'/root/.vnc/xstar

  • android取消toast_android重写toast

    大家好,又见面了,我是你们的朋友全栈君。本文实例讲述了AndroidToast通知用法。分享给大家供大家参考,具体如下:Toast在手机屏幕上向用户显示一条信息,一段时间后信息会自动消失。1.默认用法Toast.makeText(getApplicationContext(),“默认Toast样式”,Toast.LENGTH_SHORT).show();2.Fragment中的用法Toast.makeText(getActivity(),”网络连接错误,请检察网络设置”,Toast.LENGTH_LONG).show();3.自定义显示位置效果toast=Toast.makeText(getApplicationContext(),“自定义位置Toast”,Toast.LENGTH_LONG);toast.setGravity(Gravity.CENTER,0,0);toast.show();4.带图片效果toast=Toast.makeText(getApplicationContext(),“带图片的Toast”,Toast.LENGTH_LONG);toast.setGravit

  • 腾讯云内容分发网络CDN刷新目录api接口

    1.接口描述接口请求域名:cdn.tencentcloudapi.com。 PurgePathCache用于批量提交目录刷新,根据域名的加速区域进行对应区域的刷新。默认情况下境内、境外加速区域每日目录刷新额度为各100条,每次最多可提交500条。 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:PurgePathCache。 Version 是 String 公共参数,本接口取值:2018-06-06。 Region 否 String 公共参数,本接口不需要传递此参数。 Paths.N 是 ArrayofString 目录列表,需要包含协议头部http://或https:// FlushType 是 String 刷新类型fl

  • 腾讯云容器镜像服务容器镜像服务企业版

    实例相关问题为什么无法使用某个实例名称创建实例?无法使用某个实例名进行实例创建可能由以下因素造成:实例名称选取要求长度为5-50字符,仅支持小写字母、数字和-的组合,且不能以-开头或结尾,满足此规则的名称才可用于创建实例。实例名称直接决定该实例的访问域名,所以实例名称在容器镜像服务产品层级全局唯一。在新建实例时,需确保新建实例的名称不能与当前用户下已有实例的名称重合,也不能与其他用户已有实例的名称重合。部分实例名称已被保留或屏蔽,无法用于用户创建实例使用。登录实例失败怎么办?登录实例需在访问客户端中执行dockerlogin命令并输入用户名及密码。 请依次排查:1.登录指令是否输入正确?您可通过容器镜像服务控制台>实例列表>登录实例获取临时指令测试实例登录。2.访问凭证是否有效?请注意临时访问凭证有效期为1小时。详情请参见获取实例访问凭证。3.实例是否已放通登录机器所在网络?详情请参见网络访问控制概述。如果您的问题仍未解决,可通过在线客服或在线咨询联系我们。镜像相关问题容器集群如何免密拉取镜像?如果您是容器服务TKE用户,建议使用TCR插件,实现免密拉取镜像。详情请参见TK

  • 2022年10月25日23:05:48

    先汇报今天的战果,计划学14,但只学了11节,还有剩3节没学。 按这个速度,离学完它还有一定的距离。 还是得加点油。 明天早课学,下课直接回来实践。 加油赶进度把,其他没什么说的。哦,注意身体。

  • hdu 3045 斜率优化DP

    思路:dp[i]=dp[j]+sum[i]-sum[j]-(i-j)*num[j+1]; 然后就是比较斜率。 注意的时这里j+t<=i; #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #defineMaxn400010 #defineLL__int64 usingnamespacestd; LLnum[Maxn],sum[Maxn],dp[Maxn]; intque[Maxn*10]; LLGetleft(intj,intk) { returndp[j]-sum[j]+j*num[j+1]-(dp[k]-sum[k]+k*num[k+1]); } LLGetright(intj,intk) { returnnum[j+1]-num[k+1]; } intmain() { intn,t,head,rear; LLi,j; while(scanf("%d%d",&n,&t)!

  • CentOS常见问题

    1、图形界面无法启动 检查messagebus服务是否为开机启动:chkconfig--list messagebus 如果状态为不启动,则修改之:chkconfig messagebuson 启动messagebus服务:service messagebusstart 2、鼠标键盘不可用 检查haldaemon服务是否为开机启动:chkconfig--list haldaemon 如果状态为不启动,则修改之:chkconfighaldaemon on 启动haldaemon服务:servicehaldaemon start

  • 一文教你如何高效使用C语言

    使用static关键字 static关键字有两个作用,对于变量而言,表示该变量是一个静态变量,放在数据段中,即使函数运行结束,其变量也仍然存在。对于函数而言,表示该函数的作用域仅在该文件中,其他文件不可访问,这样有一个好处,就是当该文件仅仅只被本文件中的函数调用时,此时使用static关键字修饰可以避免其他函数因函数名相同而报错,也就是当使用该关键字修饰时,即使两个文件中的函数名完全相同,也不会报编译错误,例如下面有两个.c文件,分别是fun1.c和fun2.c。这两个文件中有函数swap,函数名完全相同。这样我们可以这样使用static关键字:   //fun1.cstatic void swap(int *a,int *b){    int temp;    temp=*a;    *a=*b;    *b=temp;}复制   //fun2.cstati

  • 第十三周

    1、布局管理器概念:各组件在容器中的大小以及摆放位置。实现跨平台特性并获得动态布局的效果;Java组件布局由布局管理器对象来管理;布局管理器会确定组件打大小和位置;在容器发生变化是做出动态调整。 2、布局管理器的分类     FlowLayout:流式布局管理器     BorderLayout:边界布局管理器     GridLayout:网格布局管理器     GridBagLayout:网格组布局管理器     GardLayout:卡片布局管理器     BoxLayout:箱式布局管理器     SpringLayout:弹簧布局管理器 1、FlowLayout:流式布局管理器    组件加入容器的顺序是从左到右,容器大小改变时组件大小不改变,位置会改变 网格包布局管理器

  • DNS

    NFS系统应用的优缺点说明NFS服务可以让不同的客户端挂载使用同一个共享目录,也就是将其作为共享存储使用,这样可以保证不同节点客户端数据的一致性,在集群架构环境中经常会用到。如果是windows和Linux混合环境的集群系统,可以用samba来实现。 优点:简单,容易上手,容易掌握NFS文件系统内数据是在文件系统之上的,即数据是能看得见的。部署快速,维护简单方便,且可控,满足需求的就是最好的。可靠,从软件层面上看,数据可靠性高,经久耐用。数据是在文件系统之上的。服务非常稳定 最重要的缺点是:不能扩容和单点问题缺点:读写性能问题存在单点故障,如果NFSServer荡机了,所有客户端都不能访问共享目录。这个需要负载均衡及高可用来弥补在大数据高并发的场合,NFS效率,性能有限(2千万/日以下PV(pageview)的网站不是瓶颈,除非网站架构设计太差。)客户端认证是基于IP和主机名的,权限要根据ID识别,安全性一般(用于内网则问题不大)。NFS数据是明文的,NFS本身不对数据完整性做验证。多台客户机器挂载一个NFS服务器时,连接管理维护麻烦(耦合度高)。尤其NFS服务端出问题后,所有NFS客

相关推荐

推荐阅读