代码拉取完成,页面将自动刷新
<?xml version="1.0"?>
<rss version="2.0">
<channel>
<title>Eden</title>
<link>https://luhongdeng.gitee.io</link>
<description></description>
<language>en</language>
<pubDate>Wed, 23 Dec 2020 23:28:38 +0800</pubDate>
<lastBuildDate>Wed, 23 Dec 2020 23:28:38 +0800</lastBuildDate>
<item>
<guid isPermalink="true">https://luhongdeng.gitee.io/2020/12/23/Java%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/</guid>
<title>Java网络编程</title>
<link>https://luhongdeng.gitee.io/2020/12/23/Java%E7%BD%91%E7%BB%9C%E7%BC%96%E7%A8%8B/</link>
<pubDate>Wed, 23 Dec 2020 23:28:38 +0800</pubDate>
<description><![CDATA[ <p>网络编程最主要的工作就是在发送端把信息通过规定好的协议进行组装包,在接收端按照规定好的协议把包进行解析,从而提取出对应的信息,达到通信的目的。中间最主要的就是数据包的组装,数据包的过滤,数据包的捕获,数据包的分析,当然最后再做一些处理,代码、开发工具、数据库、服务器架设和网页设计这 5 部分你都要接触。</p>
<h3 id="一-什么是网络编程"><a class="markdownIt-Anchor" href="#一-什么是网络编程">#</a> <strong>一、什么是网络编程</strong></h3>
<ul>
<li>网络编程从大的方面说就是对信息的发送到接收</li>
<li>通过操作相应的 Api 调度计算机硬件资源,并利用传输管道进行数据交换过程</li>
<li>更为具体的涉及:网络模型、套接字、数据包</li>
</ul>
<h4 id="1-7层网络模型-osi"><a class="markdownIt-Anchor" href="#1-7层网络模型-osi">#</a> 1、7 层网络模型 - OSI</h4>
<p><img data-src="1156719-afc57efbe98be4f6.png" alt="img"></p>
<ul>
<li>
<p>应用层:实现多个系统应用进程相互通信,完成一系列业务处理所需的服务。</p>
</li>
<li>
<p>表示层:把应用层提供的信息变换为能够共同理解的形式,提供字符代码、数据格式、控制信息格式、加密等的统一表示。完成一次数据的转换。</p>
</li>
<li>
<p>会话层:应用程序之间建立管理,协调系统和服务之间的交流,,使系统和服务之间有序地进行通信。</p>
</li>
<li>
<p>传输层:将数据进行分割传给网络层并保证数据段的有效性。</p>
</li>
<li>
<p>网络层:控制子网的运行,比如逻辑地址分组以及路由的选择。</p>
</li>
<li>
<p>数据链路层:物理的地址寻找,将原始低处流转换为逻辑的传输路线。</p>
</li>
<li>
<p>物理层:机械的、电子的、定时的原始比特流流传输。电信号或者光信号传输。</p>
<blockquote>
<p> 基础层:物理层、数据链路层、网络层</p>
<p> 传输层:TCP-UDP 协议层、Socket</p>
<p> 高级层:会话层、表示层、应用层</p>
</blockquote>
</li>
</ul>
<h4 id="2-网络模型-对应关系"><a class="markdownIt-Anchor" href="#2-网络模型-对应关系">#</a> 2、网络模型 - 对应关系</h4>
<p><img data-src="image-20201127210126399.png" alt="image-20201127210126399"></p>
<p>TCP/IP 协议毫无疑问是互联网的基础协议,没有它就根本不可能上网,任何和互联网有关的操作都离不开 TCP/IP 协议。</p>
<h4 id="3-socket与tcp-udp"><a class="markdownIt-Anchor" href="#3-socket与tcp-udp">#</a> 3、Socket 与 TCP、UDP</h4>
<ol>
<li>
<p>Socket</p>
<ul>
<li>
<p>简单来说是 IP 地址与端口的结合协议(RFC793)</p>
</li>
<li>
<p>一种地址与端口的结合描述协议</p>
</li>
<li>
<p>TCP/IP 协议的相关 API 的总称;是网络 Api 的集合实现</p>
</li>
<li>
<p>涵盖了:Stream Socket/Datagram Socket</p>
</li>
</ul>
</li>
<li>
<p>Socket 的作用和组成</p>
<ul>
<li>在网络传输中用于唯一标识两个端点之间的链接</li>
<li>端点:包括 IP + Port</li>
<li>4 要素:客户端地址、客户端端口、服务端地址、服务端端口</li>
</ul>
</li>
<li>
<p>Socket 传输原理</p>
<p><img data-src="image-20201127213939228.png" alt="image-20201127213939228"></p>
</li>
<li>
<p>Socket 与 TCP</p>
<ul>
<li>TCP 是面向链接的通信协议</li>
<li>通过三次握手连接,通讯完成时要拆除连接</li>
<li>由于 TCP 是面向连接的所以只能用于端到端的通讯</li>
</ul>
<blockquote>
<p>在 TCP 连接中必须要明确客户端与服务器端,由客户端向服务端发出连接请求,每次连接的创建都需要经过三次握手</p>
</blockquote>
</li>
<li>
<p>Socket 与 UDP</p>
<ul>
<li>UDP 是面向无连接的通讯协议</li>
<li>UDP 数据包括目的端口号和源端口号信息</li>
<li>由于通讯不需要连接,所以可以实现广播发送,并不局限与端到端</li>
</ul>
<blockquote>
<p>简单来说,当一台计算机向另外一台计算机发送数据时,发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。</p>
</blockquote>
<p><img data-src="image-20201127220137112.png" alt="image-20201127220137112"></p>
<p><img data-src="image-20201127220145967.png" alt="image-20201127220145967"></p>
</li>
<li>
<p>Client-Server AppLication CS 模型</p>
<ul>
<li>TCP/IP 协议中,两个进程间通讯的主要模型为:CS 模型</li>
<li>主要目的:协调网络中的计算机资源、服务模式、进程间数据共享</li>
<li>常见的:FTP、SMTP、HTTP</li>
</ul>
</li>
</ol>
<h4 id="4-tcp通信"><a class="markdownIt-Anchor" href="#4-tcp通信">#</a> 4、TCP 通信</h4>
<ol>
<li>
<p>java.net.Socket 类代表一个套接字,并且 java.net.ServerSocket 类为服务器程序提供了一种来监听客户端,并与他们建立连接的机制。</p>
</li>
<li>
<p>两台计算机之间使用套接字建立 TCP 连接过程</p>
<ul>
<li>服务器实例化一个 ServerSocket 对象,表示通过服务器上的端口通信</li>
<li>服务器调用 ServerSocket 类 的 accept()方法,该方法将一直等待,直到客户端连接到服务器上给定的端口。</li>
<li>服务器正在等待时,一个客户端实例化一个 Socket 对象,指定服务器名称和端口号来请求连接。</li>
<li>Socket 类的构造函数试图将客户端连接到指定的服务器和端口号。如果通信被建立,则在客户端创建一个 Socket 对象能够与服务器进行通信。</li>
<li>在服务器端,accept () 方法返回服务器上一个新的 socket 引用,该 socket 连接到客户端的 socket。</li>
</ul>
</li>
<li>
<p>Socket 类</p>
<p>表示客户端程序的类: <code>java.net.Socket</code></p>
<blockquote>
<p>构造方法:Socket (String host, int port) :传递服务器 IP 和端口号<br>
构造方法只要运行,就会和服务器进行连接,连接失败就抛出异常</p>
</blockquote>
<blockquote>
<p>OutputStream getOutputStream () :返回套接字的输出流,将数据输出,输出到服务器</p>
</blockquote>
<blockquote>
<p>InputStream getInputStream () :返回套接字的输入流,从服务器端读取数据<br>
客户端服务器数据交换</p>
</blockquote>
</li>
<li>
<p>ServerSocket 类</p>
<p>表示服务器程序的类: java.net.ServerSocket</p>
<blockquote>
<p>构造方法: ServerSocket (int port): 传递端口号</p>
</blockquote>
<blockquote>
<p>必须要获得客户端的套接字对象 Socket:Socket accept ()</p>
</blockquote>
</li>
<li>
<p>TCP 图片上传示例</p>
<p>客户端</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * Socket套接字连接服务器</span></span><br><span class="line"><span class="comment"> * 通过Socket获取字节输出流,写图片</span></span><br><span class="line"><span class="comment"> * 使用自己的流对象,读取图片数据源(FileInputStream、缓冲流)</span></span><br><span class="line"><span class="comment"> * 读取图片,使用字节输出流,将图片写到服务器(采用字节数组进行缓冲)</span></span><br><span class="line"><span class="comment"> * 通过Socket套接字获取字节输入流,读取服务器发回来的上传成功</span></span><br><span class="line"><span class="comment"> * 关闭资源</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TCPClient</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"> Socket socket = <span class="keyword">new</span> Socket(<span class="string">&quot;127.0.0.1&quot;</span>,<span class="number">8000</span>);</span><br><span class="line"> <span class="comment">//获取字节输出流,将图片写到服务器</span></span><br><span class="line"> OutputStream out = socket.getOutputStream();</span><br><span class="line"> <span class="comment">//创建字节输入流,读取本机上的数据源图片</span></span><br><span class="line"> FileInputStream fis = <span class="keyword">new</span> FileInputStream(<span class="string">&quot;D:\\test.jpg&quot;</span>);</span><br><span class="line"> <span class="comment">//开始读写字节数组</span></span><br><span class="line"> <span class="keyword">int</span> len = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">while</span>((len = fis.read(bytes)) != -<span class="number">1</span>)&#123;</span><br><span class="line"> out.write(bytes,<span class="number">0</span>,len);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//给服务器写终止序列,向服务端写入一个结束标志</span></span><br><span class="line"> socket.shutdownOutput();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取字节输入流,读取服务器的&quot;上传成功&quot;</span></span><br><span class="line"> InputStream in = socket.getInputStream();</span><br><span class="line"></span><br><span class="line"> len = in.read(bytes); <span class="comment">//复用byte数组</span></span><br><span class="line"> System.out.println(<span class="keyword">new</span> String(bytes,<span class="number">0</span>,len));</span><br><span class="line"></span><br><span class="line"> fis.close();</span><br><span class="line"> socket.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>服务端</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * ServerSocket套接字对象,监听端口8000</span></span><br><span class="line"><span class="comment"> * 方法accept()获取客户端的连接对象</span></span><br><span class="line"><span class="comment"> * 客户端连接对象获取字节输入流,读取客户端发送图片</span></span><br><span class="line"><span class="comment"> * 创建File对象,绑定上传文件夹(判断文件夹存在,不存在,创建文件夹)</span></span><br><span class="line"><span class="comment"> * 创建字节输出流,数据目的File对象所在文件夹</span></span><br><span class="line"><span class="comment"> * 字节流读取图片,字节流将图片写入到目的文件夹中</span></span><br><span class="line"><span class="comment"> * 将上传成功会写客户端</span></span><br><span class="line"><span class="comment"> * 关闭资源</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TCPServer</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"> ServerSocket server = <span class="keyword">new</span> ServerSocket(<span class="number">8000</span>);</span><br><span class="line"> Socket socket = server.accept();</span><br><span class="line"> <span class="comment">//通过客户端连接对象,获取字节输入流,读取客户端图片</span></span><br><span class="line"> InputStream in = socket.getInputStream();</span><br><span class="line"> <span class="comment">//将目的文件夹封装到File对象</span></span><br><span class="line"> File upload = <span class="keyword">new</span> File(<span class="string">&quot;E:\\upload&quot;</span>);</span><br><span class="line"> <span class="keyword">if</span>(! upload.exists())&#123;</span><br><span class="line"> upload.mkdirs();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//防止文件同名被覆盖,重新定义文件名字</span></span><br><span class="line"> <span class="comment">//规则: 域名+当前毫秒值+6位随机数</span></span><br><span class="line"> String filename=<span class="string">&quot;wangdao&quot;</span>+System.currentTimeMillis()+<span class="keyword">new</span> Random().nextInt(<span class="number">999999</span>)+<span class="string">&quot;.jpg&quot;</span>;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//创建字节输出流,将图片写入到目的文件夹中</span></span><br><span class="line"> FileOutputStream fos = <span class="keyword">new</span> FileOutputStream(upload+File.separator+filename);</span><br><span class="line"> <span class="comment">//读写字节数组</span></span><br><span class="line"> <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len = <span class="number">0</span>;</span><br><span class="line"> <span class="keyword">while</span>((len = in.read(bytes)) != -<span class="number">1</span>)&#123;</span><br><span class="line"> fos.write(bytes,<span class="number">0</span>,len);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">//通过客户端连接对象获取字节输出流</span></span><br><span class="line"> <span class="comment">//将&quot;上传成功&quot;写回客户端</span></span><br><span class="line"> socket.getOutputStream().write(<span class="string">&quot;上传成功!&quot;</span>.getBytes());</span><br><span class="line"></span><br><span class="line"> fos.close();</span><br><span class="line"> socket.close();</span><br><span class="line"> server.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<h4 id="4-udp通信"><a class="markdownIt-Anchor" href="#4-udp通信">#</a> 4、UDP 通信</h4>
<ol>
<li>
<p>实现封装数据的类 java.net.DatagramPacket 将数据包装或拆分,java.net.DatagramSocket 将数据包发送或接受</p>
<blockquote>
<p>DatagramPacket 构造方法:DatagramPacket ():参数字节数组,发送多少,IP 地址,端口号<br>
DatagramSocket 构造方法:DatagramSocket ():空参数<br>
方法: send () :参数数据包</p>
</blockquote>
</li>
<li>
<p>示例</p>
<p>发送端</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 创建 DatagramPacket 对象,封装数据, 接收的地址和端口</span></span><br><span class="line"><span class="comment"> * 创建 DatagramSocket 对象</span></span><br><span class="line"><span class="comment"> * 调用 DatagramSocket 类方法 send ,发送数据包</span></span><br><span class="line"><span class="comment"> * 关闭资源</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UDPSend</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException</span>&#123;</span><br><span class="line"> <span class="comment">//创建数据包对象,封装要发送的数据,接收端IP,端口 </span></span><br><span class="line"> <span class="keyword">byte</span>[] date = <span class="string">&quot;你好UDP&quot;</span>.getBytes();</span><br><span class="line"> <span class="comment">//创建InetAddress对象,封装自己的IP地址 </span></span><br><span class="line"> InetAddress inet = InetAddress.getByName(<span class="string">&quot;127.0.0.1&quot;</span>);</span><br><span class="line"> DatagramPacket dp = <span class="keyword">new</span> DatagramPacket(date, date.length, inet,<span class="number">6000</span>);</span><br><span class="line"> <span class="comment">//创建DatagramSocket对象,数据包的发送和接收对象 </span></span><br><span class="line"> DatagramSocket ds = <span class="keyword">new</span> DatagramSocket();</span><br><span class="line"> <span class="comment">//调用ds对象的方法send,发送数据包 </span></span><br><span class="line"> ds.send(dp);</span><br><span class="line"> <span class="comment">//关闭资源 </span></span><br><span class="line"> ds.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>接收端</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * 创建 DatagramSocket 对象,绑定端口号,要和发送端端口号一致</span></span><br><span class="line"><span class="comment"> * 创建字节数组,接收发来的数据</span></span><br><span class="line"><span class="comment"> * 创建数据包对象 DatagramPacket</span></span><br><span class="line"><span class="comment"> * 调用 DatagramSocket 对象方法,receive(DatagramPacket dp)接收数据,数据放在数据包中</span></span><br><span class="line"><span class="comment"> * 拆包:</span></span><br><span class="line"><span class="comment"> * 关闭资源</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">UDPReceive</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span><span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"> <span class="comment">//创建数据包传输对象DatagramSocket 绑定端口号</span></span><br><span class="line"> DatagramSocket ds = <span class="keyword">new</span> DatagramSocket(<span class="number">6000</span>);</span><br><span class="line"> <span class="comment">//创建字节数组</span></span><br><span class="line"> <span class="keyword">byte</span>[] data = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="comment">//创建数据包对象,传递字节数组</span></span><br><span class="line"> DatagramPacket dp = <span class="keyword">new</span> DatagramPacket(data, data.length);</span><br><span class="line"> <span class="comment">//调用ds对象的方法receive传递数据包</span></span><br><span class="line"> ds.receive(dp);</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取发送端的IP地址对象</span></span><br><span class="line"> String ip=dp.getAddress().getHostAddress();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取发送的端口号</span></span><br><span class="line"> <span class="keyword">int</span> port = dp.getPort();</span><br><span class="line"></span><br><span class="line"> <span class="comment">//获取接收到的字节个数</span></span><br><span class="line"> <span class="keyword">int</span> length = dp.getLength();</span><br><span class="line"> System.out.println(ip+<span class="string">&quot; &quot;</span>+port+<span class="string">&quot;:&quot;</span>+<span class="keyword">new</span> String(data,<span class="number">0</span>,length));</span><br><span class="line"> ds.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
</ol>
]]></description>
</item>
<item>
<guid isPermalink="true">https://luhongdeng.gitee.io/2020/12/23/io%E6%B5%81%E5%B8%B8%E7%94%A8%E6%93%8D%E4%BD%9C/</guid>
<title>io流常用操作..o</title>
<link>https://luhongdeng.gitee.io/2020/12/23/io%E6%B5%81%E5%B8%B8%E7%94%A8%E6%93%8D%E4%BD%9C/</link>
<pubDate>Wed, 23 Dec 2020 23:28:16 +0800</pubDate>
<description><![CDATA[ <p>I/O 输入 / 输出 (Input/Output),分为 IO 设备和 IO 接口两个部分。 在 POSIX 兼容的系统上,例如 Linux 系统 [1] ,I/O 操作可以有多种方式,比如 DIO (Direct I/O),AIO (Asynchronous I/O,异步 I/O),Memory-Mapped I/O (内存映射 I/O) 等,不同的 I/O 方式有不同的实现方式和性能,在不同的应用中可以按情况选择不同的 I/O 方式。</p>
<h4 id="一-什么是io流"><a class="markdownIt-Anchor" href="#一-什么是io流">#</a> 一、什么是 IO 流</h4>
<ul>
<li>IO 流用来处理设备之间的数据传输</li>
<li>Java 程序中对于数据的输入输出操作以 “流(Stream)” 的方式进行</li>
<li>java.io 包提供了各种的流类和接口,用以处理不同类型的数据,并通过标准的方法输入和输出数据</li>
</ul>
<ol>
<li>
<p>流的分类</p>
<ul>
<li>
<p>按操作数据单位不同分为:字节流(8bit)、字符流(16bit)</p>
</li>
<li>
<p>按数据流向流向不同分为:输入流和输出流</p>
</li>
<li>
<p>按照流的角色的不同分为:节点流、处理流</p>
<p><img data-src="image-20201128000955471.png" alt="image-20201128000955471"></p>
</li>
</ul>
<table>
<thead>
<tr>
<th style="text-align:left">抽象基类</th>
<th>字节流</th>
<th>字符流</th>
</tr>
</thead>
<tbody>
<tr>
<td style="text-align:left">输入流</td>
<td>InputStream</td>
<td>Reader</td>
</tr>
<tr>
<td style="text-align:left">输出流</td>
<td>OutputString</td>
<td>Writer</td>
</tr>
</tbody>
</table>
</li>
<li>
<p>常用的流的分类表</p>
<table>
<thead>
<tr>
<th><strong>分类</strong></th>
<th><strong>字节输入流</strong></th>
<th><strong>字节输出流</strong></th>
<th><strong>字符输入流</strong></th>
<th><strong>字符输出流</strong></th>
</tr>
</thead>
<tbody>
<tr>
<td>抽象基类</td>
<td><em>InputStream</em></td>
<td><em>OutputStream</em></td>
<td><em>Reader</em></td>
<td><em>Writer</em></td>
</tr>
<tr>
<td>访问文件</td>
<td><strong>FileInputStream</strong></td>
<td><strong>FileOutputStream</strong></td>
<td><strong>FileReader</strong></td>
<td><strong>FileWriter</strong></td>
</tr>
<tr>
<td>访问数组</td>
<td><strong>ByteArrayInputStream</strong></td>
<td><strong>ByteArrayOutputStream</strong></td>
<td><strong>CharArrayReader</strong></td>
<td><strong>CharArrayWriter</strong></td>
</tr>
<tr>
<td>访问管道</td>
<td><strong>PipedInputStream</strong></td>
<td><strong>PipedOutputStream</strong></td>
<td><strong>PipedReader</strong></td>
<td><strong>PipedWriter</strong></td>
</tr>
<tr>
<td>访问字符串</td>
<td></td>
<td></td>
<td><strong>StringReader</strong></td>
<td><strong>StringWriter</strong></td>
</tr>
<tr>
<td>缓冲流</td>
<td>BufferedInputStream</td>
<td>BufferedOutputStream</td>
<td>BufferedReader</td>
<td>BufferedWriter</td>
</tr>
<tr>
<td>转换流</td>
<td></td>
<td></td>
<td>InputStreamReader</td>
<td>OutputStreamWriter</td>
</tr>
<tr>
<td>对象流</td>
<td>ObjectInputStream</td>
<td>ObjectOutputStream</td>
<td></td>
<td></td>
</tr>
<tr>
<td>抽象基类</td>
<td><em>FilterInputStream</em></td>
<td><em>FilterOutputStream</em></td>
<td><em>FilterReader</em></td>
<td><em>FilterWriter</em></td>
</tr>
<tr>
<td>打印流</td>
<td></td>
<td>PrintStream</td>
<td></td>
<td>PrintWriter</td>
</tr>
<tr>
<td>推回输入流</td>
<td>PushbackInputStream</td>
<td></td>
<td>PushbackReader</td>
<td></td>
</tr>
<tr>
<td>特殊流</td>
<td>DataInputStream</td>
<td>DataOutputStream</td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
<blockquote>
<p>表中粗体字所标出的类代表节点流,必须直接与指定的物理节点关联。斜体字标出的类代表抽象基类,无法直接创建实例</p>
</blockquote>
</li>
</ol>
<h3 id="二-常用的io流的用法"><a class="markdownIt-Anchor" href="#二-常用的io流的用法">#</a> 二、常用的 io 流的用法</h3>
<ol>
<li>
<p>File 类</p>
<ol>
<li>
<p>构造方法</p>
<blockquote>
<p>File (String pathname):通过给定路径名字符串转换为抽象路径名来创建一个新 File 实例;</p>
<p>File (String parent, String child):根据 parent 路径名字符串 和 child 路径名字符串,创建一个新 File 实例;</p>
<p>File (File parent, String child):根据 parent 抽象路径名和 child 路径名字符串,创建一个 File 实例;</p>
</blockquote>
</li>
<li>
<p>File 类成员方法</p>
<ul>
<li>
<p>访问文件名</p>
<p>getName()</p>
<p>getPath()</p>
<p>getAbsolutePath()</p>
<p>getAbsoluteFile()</p>
<p>getParent()</p>
<p>renameTo(File newName)</p>
</li>
<li>
<p>文件检测</p>
<p>exists()</p>
<p>canWrite()</p>
<p>canRead()</p>
<p>isFile()</p>
<p>isDirectory()</p>
</li>
<li>
<p>获取常规文件信息</p>
<p>lastModified()</p>
<p>length()</p>
</li>
<li>
<p>目录操作相关</p>
<p>mkDir()</p>
<p>mkDirs()</p>
<p>list()</p>
<p>listFiles()</p>
</li>
<li>
<p>文件操作相关</p>
<p>createNewFile()</p>
<p>delete()</p>
</li>
</ul>
</li>
<li>
<p>示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">FileDemo</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"> File dir = <span class="keyword">new</span> File(<span class="string">&quot;E:\\io&quot;</span>);</span><br><span class="line"> getAllDir(dir);</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> <span class="comment">// 定义方法,实现目录的全遍历</span></span><br><span class="line"> <span class="function"><span class="keyword">private</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">getAllDir</span><span class="params">(File dir)</span> </span>&#123;</span><br><span class="line"> <span class="comment">//调用方法listFiles()对目录,dir进行遍历</span></span><br><span class="line"> File[] fileArr = dir.listFiles();</span><br><span class="line"> <span class="keyword">for</span>(File f : fileArr)&#123;</span><br><span class="line"> <span class="comment">//判断变量f表示的路径是不是文件夹,是,则递归遍历</span></span><br><span class="line"> <span class="keyword">if</span>(f.isDirectory())&#123;</span><br><span class="line"> getAllDir(f);</span><br><span class="line"> &#125;<span class="keyword">else</span>&#123;</span><br><span class="line"> System.out.println(f);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
<li>
<p>文件流</p>
<ol>
<li>
<p>FileOutputStream 类</p>
<ol>
<li>
<p>构造方法</p>
<p>FileOutputStream (File file) :创建一个向指定 File 对象表示的文件中写入数据的文件输出流。</p>
<p>FileOutputStream (File file, boolean append): 创建一个向指定 File 对象表示的文件中写入数据的文件输出流,以追加的方式写入。</p>
<p>FileOutputStream (String name) :创建一个向具有指定名称的文件中写入数据的输出文件流。</p>
<p>FileOutputStream (String name, boolean append) :创建一个向具有指定 name 的文件中写入数据的输出文件流,以追加的方式写入。</p>
<blockquote>
<p>默认情况下,当一个文件输出流对象,指向一个文件的时候,会清空文件内容。FileOutputStream 的构造方法第二个参数中加入 true 实现追加</p>
</blockquote>
</li>
<li>
<p>流对象的使用</p>
<ul>
<li>
<p>创建流子类的对象,绑定数据目的</p>
</li>
<li>
<p>调用流对象的方法 write 写</p>
</li>
<li>
<p>close 释放资源</p>
<blockquote>
<p>流对象的构造方法,可以创建文件,如果文件存在,直接覆盖</p>
</blockquote>
</li>
</ul>
</li>
</ol>
</li>
<li>
<p>FileWriter 类</p>
<ol>
<li>
<p>FileInputStream(File file)</p>
<p>FileInputStream(String name)</p>
</li>
<li>
<p>字符输出流,写数据的时候,必须要运行 flush () 刷新功能</p>
</li>
</ol>
</li>
<li>
<p>FileInputStream 类</p>
<ol>
<li>
<p>构造方法</p>
<p>FileInputStream(File file)</p>
<p>FileInputStream(String name)</p>
</li>
<li>
<p>流对象的使用</p>
<ul>
<li>
<p>创建字节输入流的子类对象</p>
</li>
<li>
<p>调用读取方法 read 读取</p>
</li>
<li>
<p>close 释放资源</p>
<blockquote>
<p>在 read 读取的过程中可以使用一次读一个字节和一次读取一个字节数组两种方式</p>
</blockquote>
</li>
</ul>
</li>
</ol>
</li>
<li>
<p>FileReader 类</p>
<ol>
<li>
<p>构造方法</p>
<p>FileReader(String fileName)</p>
<p>FileWriter(File file, boolean append)</p>
</li>
<li>
<p>流对象的使用</p>
<ul>
<li>创建字节输入流的子类对象</li>
<li>调用读取方法 read 读取</li>
<li>close 释放资源</li>
</ul>
</li>
</ol>
<blockquote>
<p>FileInputStream 和 FileReader 使用 int read (byte [] b) 读取一个字节,读到结尾返回 - 1,可以使用 read (byte [] b, int off, int len) 读取多个字节存入数组中,数组的缓冲作用可以提高效率</p>
</blockquote>
<blockquote>
<p>write (byte [] b): 将 b.length 个字节从指定的 byte 数组写入此输出流</p>
<p>write (byte [] b, int off, int len):将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此输出流。</p>
<p>write (int b): 将指定的字节写入此输出流。</p>
</blockquote>
</li>
<li>
<p>示例</p>
<p>字节文本复制</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Copy_1</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"> <span class="keyword">long</span> s = System.currentTimeMillis();</span><br><span class="line"> FileInputStream fis = <span class="keyword">null</span>;</span><br><span class="line"> FileOutputStream fos = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span>&#123;</span><br><span class="line"> fis = <span class="keyword">new</span> FileInputStream(<span class="string">&quot;D:\\test.mp3&quot;</span>);</span><br><span class="line"> fos = <span class="keyword">new</span> FileOutputStream(<span class="string">&quot;E:\\test.mp3&quot;</span>);</span><br><span class="line"> <span class="comment">//定义字节数组,缓冲</span></span><br><span class="line"> <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>*<span class="number">10</span>];</span><br><span class="line"> <span class="comment">//读取数组,写入数组</span></span><br><span class="line"> <span class="keyword">int</span> len = <span class="number">0</span> ;</span><br><span class="line"> <span class="keyword">while</span>((len = fis.read(bytes))!=-<span class="number">1</span>)&#123;</span><br><span class="line"> fos.write(bytes, <span class="number">0</span>, len);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;<span class="keyword">catch</span>(IOException e)&#123;</span><br><span class="line"> System.out.println(e);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;文件复制失败&quot;</span>);</span><br><span class="line"> &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line"> <span class="keyword">try</span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(fos!=<span class="keyword">null</span>)</span><br><span class="line"> fos.close();</span><br><span class="line"> &#125;<span class="keyword">catch</span>(IOException e)&#123;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;释放资源失败&quot;</span>);</span><br><span class="line"> &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line"> <span class="keyword">try</span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(fis!=<span class="keyword">null</span>)</span><br><span class="line"> fis.close();</span><br><span class="line"> &#125;<span class="keyword">catch</span>(IOException e)&#123;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;释放资源失败&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="keyword">long</span> e = System.currentTimeMillis();</span><br><span class="line"> System.out.println(e-s);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>字符文本复制</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Copy_2</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line"> FileReader fr = <span class="keyword">null</span>;</span><br><span class="line"> FileWriter fw = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">try</span>&#123;</span><br><span class="line"> fr = <span class="keyword">new</span> FileReader(<span class="string">&quot;c:\\1.txt&quot;</span>);</span><br><span class="line"> fw = <span class="keyword">new</span> FileWriter(<span class="string">&quot;d:\\1.txt&quot;</span>);</span><br><span class="line"> <span class="keyword">char</span>[] cbuf = <span class="keyword">new</span> <span class="keyword">char</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len = <span class="number">0</span> ;</span><br><span class="line"> <span class="keyword">while</span>(( len = fr.read(cbuf))!=-<span class="number">1</span>)&#123;</span><br><span class="line"> fw.write(cbuf, <span class="number">0</span>, len);</span><br><span class="line"> fw.flush();</span><br><span class="line"> &#125;</span><br><span class="line"></span><br><span class="line"> &#125;<span class="keyword">catch</span>(IOException ex)&#123;</span><br><span class="line"> System.out.println(ex);</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;复制失败&quot;</span>);</span><br><span class="line"> &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line"> <span class="keyword">try</span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(fw!=<span class="keyword">null</span>)</span><br><span class="line"> fw.close();</span><br><span class="line"> &#125;<span class="keyword">catch</span>(IOException ex)&#123;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;释放资源失败&quot;</span>);</span><br><span class="line"> &#125;<span class="keyword">finally</span>&#123;</span><br><span class="line"> <span class="keyword">try</span>&#123;</span><br><span class="line"> <span class="keyword">if</span>(fr!=<span class="keyword">null</span>)</span><br><span class="line"> fr.close();</span><br><span class="line"> &#125;<span class="keyword">catch</span>(IOException ex)&#123;</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> RuntimeException(<span class="string">&quot;释放资源失败&quot;</span>);</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
<li>
<p>缓冲流</p>
<p>可提高 IO 流的读写速度<br>
分为字节缓冲流与字符缓冲流</p>
<ol>
<li>
<p>字节缓冲流 BufferedOutputStream / BufferedInputStream</p>
<ol>
<li>
<p>构造方法</p>
<p>BufferedOuputStream (OuputStream out):可以传递任意的字节输出流</p>
<p>BufferedInputStream (InputStream in):可以传递任意的字节输入流</p>
</li>
<li>
<p>写入 write 字节或 write 字节数组,read () 单个字节或字节数组</p>
</li>
</ol>
</li>
<li>
<p>字符缓冲流 BufferedWriter/ BufferedReader</p>
<ol>
<li>
<p>构造方法</p>
<p>BufferedWriter (Writer w):传递任意字符输出流</p>
<p>BufferedReader (Reader r):可以任意的字符输入流</p>
</li>
<li>
<p>写入 write 字节或 write 字节数组,read () 单个字节或字节数组</p>
</li>
<li>
<p>BufferedWriter— 特有方法 newLine 换行</p>
</li>
</ol>
<blockquote>
<p>在使用缓冲流后要关闭缓冲流,而且在关闭的同时也会关闭文件流</p>
</blockquote>
</li>
<li>
<p>示例</p>
<p>字节流文件复制</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Copy</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span><span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"> <span class="keyword">long</span> s = System.currentTimeMillis();</span><br><span class="line"> BufferedInputStream bis = <span class="keyword">new</span> BufferedInputStream(<span class="keyword">new</span> FileInputStream(<span class="keyword">new</span> File(<span class="string">&quot;c:\\q.exe&quot;</span>)));</span><br><span class="line"> BufferedOutputStream bos = <span class="keyword">new</span> BufferedOutputStream(<span class="keyword">new</span> FileOutputStream(<span class="keyword">new</span> File(<span class="string">&quot;d:\\q.exe&quot;</span>)));</span><br><span class="line"> <span class="keyword">int</span> len = <span class="number">0</span> ;</span><br><span class="line"> <span class="keyword">byte</span>[] bytes = <span class="keyword">new</span> <span class="keyword">byte</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">while</span>((len = bis.read(bytes))!=-<span class="number">1</span>)&#123;</span><br><span class="line"> bos.write(bytes,<span class="number">0</span>,len);</span><br><span class="line"> &#125;</span><br><span class="line"> bos.close();</span><br><span class="line"> bis.close();</span><br><span class="line"> <span class="keyword">long</span> e = System.currentTimeMillis();</span><br><span class="line"> System.out.println(e-s);</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>字符流文件复制</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Copy_1</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException</span>&#123;</span><br><span class="line"> BufferedReader bfr = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> FileReader(<span class="string">&quot;c:\\w.log&quot;</span>)); </span><br><span class="line"> BufferedWriter bfw = <span class="keyword">new</span> BufferedWriter(<span class="keyword">new</span> FileWriter(<span class="string">&quot;d:\\w.log&quot;</span>));</span><br><span class="line"> <span class="comment">//读取文本行, 读一行,写一行,写换行</span></span><br><span class="line"> String line = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">while</span>((line = bfr.readLine())!=<span class="keyword">null</span>)&#123;</span><br><span class="line"> bfw.write(line);</span><br><span class="line"> bfw.newLine();</span><br><span class="line"> bfw.flush();</span><br><span class="line"> &#125;</span><br><span class="line"> bfw.close();</span><br><span class="line"> bfr.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
<li>
<p>对象流</p>
<ul>
<li>对象的序列化:对象中的数据以流的形式写入到文件中保存过程称为写出对象</li>
<li>ObjectOutputStream 将对象写入文件中,实现序列化</li>
<li>对象的反序列化:在文件中以流的形式将对象读出来,读取对象</li>
<li>ObjectInputStream 将文件对象读取出来</li>
</ul>
<ol>
<li>
<p>构造方法</p>
<p>ObjectOutputStream (OutputSteam out):传递任意的 字节输出流</p>
<p>ObjectInputStream (InputStream in):传递任意的 字节输入流,输入流封装文件</p>
</li>
<li>
<p>writeObject (Object obj):写出对象 ;Object readObject (): 读取对象</p>
</li>
<li>
<p>示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">objectOutputStreamTest</span><span class="params">()</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"> <span class="comment">// 1.创建字节输出流对象,封装文件</span></span><br><span class="line"> FileOutputStream fos = <span class="keyword">new</span> FileOutputStream(<span class="string">&quot;xuliehua.properties&quot;</span>);</span><br><span class="line"> <span class="comment">// 2.创建写出对象的序列化流的对象</span></span><br><span class="line"> ObjectOutputStream oos = <span class="keyword">new</span> ObjectOutputStream(fos);</span><br><span class="line"> Person per = <span class="keyword">new</span> Person(<span class="string">&quot;狂徒张三&quot;</span>, <span class="number">18</span>);</span><br><span class="line"> <span class="comment">// 3.调用序列化流的方法writeObject, 写出对象</span></span><br><span class="line"> oos.writeObject(per);</span><br><span class="line"> <span class="comment">// 4.关闭流操作</span></span><br><span class="line"> oos.close();</span><br><span class="line"> System.out.println(per.toString());</span><br><span class="line">&#125;</span><br><span class="line"> </span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">objectInputStreamTest</span><span class="params">()</span> <span class="keyword">throws</span> IOException, ClassNotFoundException </span>&#123;</span><br><span class="line"> <span class="comment">// 1.创建字节输入流对象</span></span><br><span class="line"> FileInputStream fis = <span class="keyword">new</span> FileInputStream(<span class="string">&quot;xuliehua.properties&quot;</span>);</span><br><span class="line"> <span class="comment">// 2.创建反序列化流,构造方法中传递,字节输入流</span></span><br><span class="line"> ObjectInputStream ois = <span class="keyword">new</span> ObjectInputStream(fis);</span><br><span class="line"> <span class="comment">// 3.调用方法readObject()读取对象</span></span><br><span class="line"> Object obj = ois.readObject();</span><br><span class="line"> System.out.println(obj);</span><br><span class="line"> <span class="comment">// 4.关闭流操作</span></span><br><span class="line"> ois.close();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
<li>
<p>转换流</p>
<ol>
<li>
<p>构造方法</p>
<p>OutputStreamWriter (OuputStream out):接收所有的字节输出流</p>
<p>OutputStreamWriter(OutputStream out, String charsetName)</p>
<blockquote>
<p>FileOutputStream</p>
</blockquote>
<p>InputStreamReader (InputStream in):接收所有的 字节输入流</p>
<p>InputStreamReader (InputStream in,String charsetName) : 传递编码表的名字</p>
<blockquote>
<p>FileInputStream</p>
</blockquote>
</li>
<li>
<p>写入 write 字节或 write 字节数组,read () 单个字节或字节数组</p>
<blockquote>
<p>OutputStreamWriter 和 InputStreamReader 是字符和字节的桥梁:也可以称之为字符转换流。字符转换流原理:字节流 + 编码表</p>
<p>FileWriter\ 和 FileReader:作为子类,仅作为操作字符文件的便捷类存在。当操作的字符文件,使用的是默认编码表时可以不用父类,而直接用子类就完成操作了,简化了代码</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">InputStreamReader isr = <span class="keyword">new</span> InputStreamReader(<span class="keyword">new</span> FileInputStream(<span class="string">&quot;a.txt&quot;</span>));<span class="comment">//默认字符集。</span></span><br><span class="line">InputStreamReader isr = <span class="keyword">new</span> InputStreamReader(<span class="keyword">new</span> FileInputStream(<span class="string">&quot;a.txt&quot;</span>),<span class="string">&quot;GBK&quot;</span>);<span class="comment">//指定GBK字符集。</span></span><br><span class="line">FileReader fr = <span class="keyword">new</span> FileReader(<span class="string">&quot;a.txt&quot;</span>);</span><br></pre></td></tr></table></figure>
</blockquote>
</li>
<li>
<p>示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">InputStreamReaderDemo</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException </span>&#123;</span><br><span class="line"> readUTF();</span><br><span class="line"> &#125;</span><br><span class="line"> <span class="comment">//转换流,InputSteamReader读取文本,采用UTF-8编码表,读取文件utf</span></span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">readUTF</span><span class="params">()</span><span class="keyword">throws</span> IOException</span>&#123;</span><br><span class="line"> <span class="comment">//创建字节输入流,传递文本文件</span></span><br><span class="line"> FileInputStream fis = <span class="keyword">new</span> FileInputStream(<span class="string">&quot;c:\\utf.txt&quot;</span>);</span><br><span class="line"> <span class="comment">//创建转换流对象,构造方法中,包装字节输入流,同时写编码表名</span></span><br><span class="line"> InputStreamReader isr = <span class="keyword">new</span> InputStreamReader(fis,<span class="string">&quot;UTF-8&quot;</span>);</span><br><span class="line"> <span class="keyword">char</span>[] ch = <span class="keyword">new</span> <span class="keyword">char</span>[<span class="number">1024</span>];</span><br><span class="line"> <span class="keyword">int</span> len = isr.read(ch);</span><br><span class="line"> System.out.println(<span class="keyword">new</span> String(ch,<span class="number">0</span>,len));</span><br><span class="line"> isr.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
</li>
<li>
<p>打印流</p>
<ol>
<li>
<p>构造方法</p>
<p>PrintStream(OutputStream)</p>
<p>PrintWriter(OutputStream)</p>
</li>
<li>
<p>print (String str): 输出任意类型的数据;</p>
<p>println (String str): 输出任意类型的数据,自动写入换行操作</p>
</li>
<li>
<p>特点</p>
<ul>
<li>
<p>此流不负责数据源,只负责数据目的</p>
</li>
<li>
<p>可以操作任意类型的数据。(boolean, int, long, float, double)</p>
</li>
<li>
<p>打印流,可以开启自动刷新功能,满足两个条件:</p>
<ul>
<li>
<p>使用特定的构造方法,打开打印流的自动刷新,输出的数据目的必须是流对象:OutputStream Writer</p>
</li>
<li>
<p>必须调用 println,printf,format 三个方法中的一个,启用自动刷新</p>
</li>
</ul>
</li>
<li>
<p>使用特定的构造方法,打开打印流的自动刷新,输出的数据目的必须是流对象:OutputStream Writer</p>
</li>
<li>
<p>必须调用 println,printf,format 三个方法中的一个,启用自动刷新</p>
</li>
<li>
<p>为其他输出流,添加功能</p>
</li>
<li>
<p>永远不会抛出 IOException,但是可能抛出别的异常</p>
</li>
</ul>
</li>
</ol>
</li>
<li>
<p>示例</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PrintWriterDemo1</span> </span>&#123;</span><br><span class="line"> <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> <span class="keyword">throws</span> IOException</span>&#123;</span><br><span class="line"> BufferedReader bfr = <span class="keyword">new</span> BufferedReader(<span class="keyword">new</span> FileReader(<span class="string">&quot;c:\\a.txt&quot;</span>));</span><br><span class="line"> PrintWriter pw = <span class="keyword">new</span> PrintWriter(<span class="keyword">new</span> FileWriter(<span class="string">&quot;d:\\a.txt&quot;</span>),<span class="keyword">true</span>);</span><br><span class="line"> String line = <span class="keyword">null</span>;</span><br><span class="line"> <span class="keyword">while</span>((line = bfr.readLine())!=<span class="keyword">null</span>)&#123;</span><br><span class="line"> pw.println(line);</span><br><span class="line"> &#125;</span><br><span class="line"> pw.close();</span><br><span class="line"> bfr.close();</span><br><span class="line"> &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
</li>
</ol>
]]></description>
</item>
<item>
<guid isPermalink="true">https://luhongdeng.gitee.io/2020/12/23/dubbo/</guid>
<title>dubbo</title>
<link>https://luhongdeng.gitee.io/2020/12/23/dubbo/</link>
<pubDate>Wed, 23 Dec 2020 22:46:37 +0800</pubDate>
<description><![CDATA[ <p>Dubbo (读音 [ˈdʌbəʊ]) 是阿里巴巴公司开源的一个高性能优秀的<span class="exturl" data-url="aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS8lRTYlOUMlOEQlRTUlOEElQTElRTYlQTElODYlRTYlOUUlQjY=">服务框架</span>,使得应用可通过高性能的 RPC 实现服务的输出和输入功能,可以和 [1] <span class="exturl" data-url="aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS9TcHJpbmc=">Spring</span> 框架无缝集成。</p>
<p>Dubbo 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。</p>
<h2 id="什么是dubbo"><a class="markdownIt-Anchor" href="#什么是dubbo">#</a> 什么是 dubbo</h2>
<ul>
<li>
<p>开源分布式服务框架</p>
</li>
<li>
<p>微服务生态中的重要组件</p>
</li>
<li>
<p>高性能、轻量级的开源 Java RPC 框架</p>
</li>
<li>
<p>具有面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现能力</p>
<ol>
<li>
<p>分布式系统</p>
<p>分布式系统(distributed system)是建立在网络之上的软件系统。正是因为软件的特性,所以分布式系统具有高度的内聚性和透明性。因此,网络和分布式系统之间的区别更多的在于高层软件(特别是操作系统),而不是硬件。</p>
<p><img data-src="image-20201202005354520.png" alt="image-20201202005354520"></p>
</li>
<li>
<p>架构的发展历史</p>
<p><img data-src="image-20201201235840015.png" alt="image-20201201235840015"></p>
</li>
<li>
<p>RPC 介绍</p>
<p>RPC【Remote Procedure Call】是指远程过程调用,是一种进程间通信方式,他是一种技术的思想,而不是规范。它允许程序调用另一个地址空间(通常是共享网络的另一台机器上)的过程或函数,而不用程序员显式编码这个远程调用的细节。即程序员无论是调用本地的还是远程的函数,本质上编写的调用代码基本相同</p>
<ul>
<li>
<p>RPC 指远程过程调用</p>
</li>
<li>
<p>调用其他机器上的程序和调用本地的程序一样方便</p>
</li>
<li>
<p>传输效率</p>
</li>
<li>
<p>性能消耗</p>
</li>
<li>
<p>负载均衡</p>
</li>
</ul>
<p><img data-src="image-20201202001425293.png" alt="image-20201202001425293"></p>
<p>一次完整的 RPC 调用流程如下:</p>
<blockquote>
<ol>
<li>消费者 client 调用以本地调用方式调用服务;</li>
</ol>
</blockquote>
</li>
</ol>
<blockquote>
<ol start="2">
<li>client stub 接收到调用后负责将方法、参数等组装成能够进行网络传输的消息体;</li>
<li>client stub 找到服务地址,并将消息发送到服务端;</li>
</ol>
<p>4)server stub 收到消息后进行解码;</p>
<p>5)server stub 根据解码结果调用本地的服务;</p>
<p>6)提供者 server 执行并将结果返回给 server stub;</p>
<p>7)server stub 将返回结果打包成消息并发送至消费方;</p>
<p>8)client stub 接收到消息,并进行解码;</p>
<p>9)服务消费方得到最终结果</p>
</blockquote>
<ol start="4">
<li>
<p>RPC netty 通信原理</p>
<ul>
<li>netty 基于 NIO 的多路复用模型来实现</li>
</ul>
<blockquote>
<ol>
<li>Connect</li>
<li>Accept</li>
<li>Read</li>
<li>Write</li>
</ol>
</blockquote>
<p><img data-src="image-20201202221418213.png" alt="image-20201202221418213"></p>
</li>
</ol>
</li>
</ul>
<h2 id="dubbo工作原理"><a class="markdownIt-Anchor" href="#dubbo工作原理">#</a> Dubbo 工作原理</h2>
<ol>
<li>
<p>基本概念</p>
<p><img data-src="image-20201202225415858.png" alt="image-20201202225415858"></p>
<p>调用关系说明</p>
<ul>
<li>
<p>服务容器负责启动,加载,运行服务提供者。</p>
</li>
<li>
<p>服务提供者在启动时,向注册中心注册自己提供的服务。</p>
</li>
<li>
<p>服务消费者在启动时,向注册中心订阅自己所需的服务。</p>
</li>
<li>
<p>注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。</p>
</li>
<li>
<p>服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。</p>
</li>
<li>
<p>服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。</p>
</li>
</ul>
</li>
<li>
<p>dubbo 的注册中心和监控中心工具</p>
<p>启动 zookper、dubbo-admin、dubbo-monitor-simple</p>
</li>
<li>
<p>dubbo 改造</p>
<ul>
<li>
<p>提供者</p>
<blockquote>
<ol>
<li>指定当前服务 / 应用的名字</li>
<li>指定注册中心的位置</li>
<li>指定通信规则</li>
<li>连接监控中心</li>
<li>声明需要暴露的服务接口</li>
<li>服务的具体实现</li>
</ol>
</blockquote>
</li>
<li>
<p>消费者</p>
<blockquote>
<ol>
<li>指定当前服务 / 应用的名字</li>
<li>指定注册中心的位置</li>
<li>指定通信规则</li>
<li>连接监控中心</li>
<li>链接到当前需要的服务接口</li>
</ol>
</blockquote>
</li>
</ul>
</li>
<li>
<p>dubbo 常用配置</p>
<p><img data-src="image-20201202231836939.png" alt="image-20201202231836939"></p>
<ul>
<li>
<p>retries 重试次数</p>
</li>
<li>
<p>timeout 超时时间</p>
</li>
<li>
<p>version 版本</p>
</li>
</ul>
</li>
<li>
<p>dubbo 高可用配置</p>
<ul>
<li>dubbo 直连</li>
<li>dubbo 负载均衡</li>
<li>dubbo 集群容错</li>
</ul>
</li>
</ol>
<h2 id="dubbo框架设计"><a class="markdownIt-Anchor" href="#dubbo框架设计">#</a> dubbo 框架设计</h2>
<p><img data-src="image-20201202004152826.png" alt="image-20201202004152826"></p>
<ol>
<li>
<p>config 配置层:</p>
<blockquote>
<p>对外配置接口,解析配置文件的信息以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类</p>
</blockquote>
</li>
<li>
<p>proxy 服务代理层:</p>
<blockquote>
<p>服务接口透明代理,生成服务的客户端代理对象和服务器端目标的代理对象,互相的调用方法</p>
</blockquote>
</li>
<li>
<p>registry 注册中心层</p>
<blockquote>
<p>封装服务地址的注册与发现</p>
</blockquote>
</li>
<li>
<p>cluster 路由层</p>
<blockquote>
<p>封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance</p>
</blockquote>
</li>
<li>
<p>monitor 监控层</p>
<blockquote>
<p>RPC 调用次数和调用时间监控,可以界面展示,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService</p>
</blockquote>
</li>
<li>
<p>protocol 远程调用层</p>
<blockquote>
<p>封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter</p>
</blockquote>
</li>
<li>
<p>exchange 信息交换层</p>
<blockquote>
<p>封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer</p>
</blockquote>
</li>
<li>
<p>transport 网络传输层</p>
<blockquote>
<p>抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec</p>
</blockquote>
</li>
<li>
<p>serialize 数据序列化层</p>
<blockquote>
<p>可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool</p>
</blockquote>
</li>
<li>
<p>config 配置层:</p>
<blockquote>
<p>对外配置接口,以 ServiceConfig, ReferenceConfig 为中心,可以直接初始化配置类,也可以通过 spring 解析配置生成配置类</p>
</blockquote>
</li>
<li>
<p>proxy 服务代理层:</p>
<blockquote>
<p>服务接口透明代理,生成服务的客户端 Stub 和服务器端 Skeleton, 以 ServiceProxy 为中心,扩展接口为 ProxyFactory</p>
</blockquote>
</li>
<li>
<p>registry 注册中心层</p>
<blockquote>
<p>封装服务地址的注册与发现,以服务 URL 为中心,扩展接口为 RegistryFactory, Registry, RegistryService</p>
</blockquote>
</li>
<li>
<p>cluster 路由层</p>
<blockquote>
<p>封装多个提供者的路由及负载均衡,并桥接注册中心,以 Invoker 为中心,扩展接口为 Cluster, Directory, Router, LoadBalance</p>
</blockquote>
</li>
<li>
<p>monitor 监控层</p>
<blockquote>
<p>RPC 调用次数和调用时间监控,以 Statistics 为中心,扩展接口为 MonitorFactory, Monitor, MonitorService</p>
</blockquote>
</li>
<li>
<p>protocol 远程调用层</p>
<blockquote>
<p>封装 RPC 调用,以 Invocation, Result 为中心,扩展接口为 Protocol, Invoker, Exporter</p>
</blockquote>
</li>
<li>
<p>exchange 信息交换层</p>
<blockquote>
<p>封装请求响应模式,同步转异步,以 Request, Response 为中心,扩展接口为 Exchanger, ExchangeChannel, ExchangeClient, ExchangeServer</p>
</blockquote>
</li>
<li>
<p>transport 网络传输层</p>
<blockquote>
<p>抽象 mina 和 netty 为统一接口,以 Message 为中心,扩展接口为 Channel, Transporter, Client, Server, Codec</p>
</blockquote>
</li>
<li>
<p>serialize 数据序列化层</p>
<blockquote>
<p>可复用的一些工具,扩展接口为 Serialization, ObjectInput, ObjectOutput, ThreadPool</p>
</blockquote>
</li>
</ol>
]]></description>
</item>
<item>
<guid isPermalink="true">https://luhongdeng.gitee.io/2020/12/23/zookeeper/</guid>
<title>zookeeper</title>
<link>https://luhongdeng.gitee.io/2020/12/23/zookeeper/</link>
<pubDate>Wed, 23 Dec 2020 22:46:37 +0800</pubDate>
<description><![CDATA[ <p>ZooKeeper 是一个<span class="exturl" data-url="aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS8lRTUlODglODYlRTUlQjglODMlRTUlQkMlOEYvMTkyNzYyMzI=">分布式</span>的,开放源码的<span class="exturl" data-url="aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS8lRTUlODglODYlRTUlQjglODMlRTUlQkMlOEYlRTUlQkElOTQlRTclOTQlQTglRTclQTglOEIlRTUlQkElOEYvOTg1NDQyOQ==">分布式应用程序</span>协调服务,是<span class="exturl" data-url="aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS9Hb29nbGU="> Google</span> 的 Chubby 一个<span class="exturl" data-url="aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS8lRTUlQkMlODAlRTYlQkElOTAvMjQ2MzM5">开源</span>的实现,是 Hadoop 和<span class="exturl" data-url="aHR0cHM6Ly9iYWlrZS5iYWlkdS5jb20vaXRlbS9IYmFzZS83NjcwMjEz"> Hbase</span> 的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。</p>
<p>ZooKeeper 的目标就是封装好复杂易出错的关键服务,将简单易用的接口和性能高效、功能稳定的系统提供给用户。</p>
<h3 id="1-理解zookeeper"><a class="markdownIt-Anchor" href="#1-理解zookeeper">#</a> 1、理解 zookeeper</h3>
<ol>
<li>
<h5 id="为什么需要zookeeper"><a class="markdownIt-Anchor" href="#为什么需要zookeeper">#</a> 为什么需要 Zookeeper</h5>
<p>我们需要一个像单机但是又比单机更可靠的东西</p>
<ul>
<li>leader 在团队中的协调作用</li>
<li>内存、单机</li>
<li>集群、可靠</li>
<li>当信息还没同步完成时,不对外提供服务</li>
<li>同步时间压缩的更短</li>
<li>比如我们搭建了一个数据库集群,里面有一个 Master,多个 Slave,Master 负责写,Slave 只读,我们需要一个系统,来告诉客户端,哪个是 Master。如果是单机一旦这个机器挂了,客户端将无法知道到底哪个是 Master。于是开始进行拓展,拓展成三台服务器的集群。如果我在其中一台机器修改了 Master 的 ip,同步到其他两台。需要这个存储 master 信息的服务器集群,做到当信息还没同步完成时,不对外提供服务,阻塞住查询请求,等待信息同步完成,再给查询请求返回信息。</li>
</ul>
</li>
<li>
<h5 id="zookeeper诞生历史"><a class="markdownIt-Anchor" href="#zookeeper诞生历史">#</a> Zookeeper 诞生历史</h5>
<blockquote>
<p>ZooKeeper 最早起源于雅虎研究院的一个研究小组。在当时,研究人员发现,在雅虎内部很多大型系统基本都需要依赖一个类似的系统来进行分布式协调,但是这些系统往往都存在分布式单点问题。所以,雅虎的开发人员就试图开发一个通用的无单点问题的分布式协调框架,以便让开发人员将精力集中在处理业务逻辑上。<br>
关于 “ZooKeeper” 这个项目的名字,其实也有一段趣闻。在立项初期,考虑到之前内部很多项目都是使用动物的名字来命名的(例如著名的 Pig 项目), 雅虎的工程师希望给这个项目也取一个动物的名字。时任研究院的首席科学家 RaghuRamakrishnan 开玩笑地说:“在这样下去,我们这儿就变成动物园了!” 此话一出,大家纷纷表示就叫动物园管理员吧一一一因为各个以动物命名的分布式组件放在一起,雅虎的整个分布式系统看上去就像一个大型的动物园了,而 ZooKeeper 正好要用来进行分布式环境的协调一一于是,ZooKeeper 的名字也就由此诞生了。</p>
</blockquote>
<p>无单点问题的分布式协调框架,精力集中在处理业务逻辑</p>
</li>
<li>
<h5 id="zookeeper是什么"><a class="markdownIt-Anchor" href="#zookeeper是什么">#</a> Zookeeper 是什么</h5>
<ul>
<li>
<p>ZooKeeper: A Distributed Coordination Service for Distributed Applications</p>
</li>
<li>
<p>ZooKeeper 是开源的高性能的分布式应用协调系统,一个高性能的分布式数据一致性解决方案</p>
</li>
</ul>
</li>
<li>
<h5 id="zookeeper5大特点"><a class="markdownIt-Anchor" href="#zookeeper5大特点">#</a> Zookeeper5 大特点</h5>
<ul>
<li>
<p>顺序一致性</p>
<blockquote>
<p>客户端发给服务端的消息 Zookeeper 会按照发送消息一条一条的执行</p>
</blockquote>
</li>
<li>
<p>原子性</p>
<blockquote>
<p>一系列的操作要么成功要么不成功,不可能完成一部分一部分失败,而且在完成之前对外是没有显现的</p>
</blockquote>
</li>
<li>
<p>单一视图</p>
<blockquote>
<p>在 Zookeeper 集群中无论链接的是哪个,所看到的都是一致的</p>
</blockquote>
</li>
<li>
<p>可靠性</p>
<blockquote>
<p>节点数据会一直保留,直到另外的操作写掉了才发生变化</p>
</blockquote>
</li>
<li>
<p>及时性</p>
<blockquote>
<p>保证一定的时间段内客户端能从服务器读到最新的状态</p>
</blockquote>
</li>
</ul>
</li>
<li>
<p>集群架构</p>
<p><img data-src="https://image-static.segmentfault.com/260/947/2609475003-5cd8e248e889b_articlex" alt="img"></p>
</li>
<li>
<p>Zookeeper 的作用</p>
<ol>
<li>
<p>CAPCAP 原则又称 CAP 定理,指的是在一个分布式系统中,一致性(Consistency)、可用性(Availability)、分区容错性(Partition tolerance)。CAP 原则指的是,这三个要素最多只能同时实现两点,不可能三者兼顾。</p>
<blockquote>
<p>Zookeeper 采用一致性加分区容错性,能得到一致的数据结果,同时系统对网络具备容错性,但它不能保证每次服务请求的可用性</p>
</blockquote>
</li>
<li>
<p>Zookeeper 的作用</p>
<p><img data-src="image-20201207232525261.png" alt="image-20201207232525261"></p>
<ul>
<li>分布式服务注册与订阅</li>
<li>统一文件配置</li>
<li>生成分布式唯一 ID</li>
<li>Master 节点选举</li>
<li>分布式锁</li>
</ul>
</li>
</ol>
</li>
</ol>
<h3 id="2-安装-配置"><a class="markdownIt-Anchor" href="#2-安装-配置">#</a> 2、安装、配置</h3>
<h3 id="3-节点znode基本数据模型"><a class="markdownIt-Anchor" href="#3-节点znode基本数据模型">#</a> 3、节点 znode(基本数据模型)</h3>
<ol>
<li>
<p>树结构,在节点中保存属性信息、路径信息和数据信息</p>
<p><img data-src="image-20201207233203581.png" alt="image-20201207233203581"></p>
</li>
<li>
<p>节点性质</p>
<p>每个节点都是树形结构,相当于 Linux 的文件目录</p>
<p>每个节点都是 znode,里面包含数据,也可以有子节点</p>
<p>点分为永久节点和临时节点(session 失效,也就是客户端端口后,临时节点消失)</p>
<p>每个 znode 都有版本号,每当数据变化,版本号会累加(乐观锁)</p>
<p>删除或修改节点,版本号不匹配的话(版本号已过期),会报错</p>
<p>每个节点储存的数据不易过大,几 k 即可</p>
<p>节点可以设置权限,用来限制用户的访问</p>
<p>Zookeeper 保证读和写都是原子操作,且每次读写操作都是对数据的完整性读取或完整写入</p>
</li>
<li>
<p>节点类型</p>
<p>持久节点</p>
<p>临时节点 集群管理</p>
<p>顺序节点(可以是持久也可以是非持久)</p>
<p><img data-src="image-20201207234551307.png" alt="image-20201207234551307"></p>
</li>
<li>
<p>节点属性</p>
<p>dataVersion</p>
<p>cversion</p>
<p>aclVersion</p>
</li>
</ol>
<h3 id="4-常用命令"><a class="markdownIt-Anchor" href="#4-常用命令">#</a> 4、常用命令</h3>
<ol>
<li>启动</li>
<li>链接 Zookeeper</li>
<li>查看节点 ls</li>
<li>查看节点状态 stat</li>
<li>查看节点的数据和状态 get</li>
<li>创建 create</li>
<li>删除 delete</li>
<li>修改节点 set</li>
<li>创建顺序节点 -s</li>
<li>创建临时节点 -e</li>
<li>条件更新 -v dataVersion</li>
</ol>
<h3 id="5-watch机制"><a class="markdownIt-Anchor" href="#5-watch机制">#</a> 5、watch 机制</h3>
<p><img data-src="image-20201208000706579.png" alt="image-20201208000706579"></p>
<p>使用场景:统一资源配置</p>
<p>watcher 事件类型</p>
<p><img data-src="image-20201208001026444.png" alt="image-20201208001026444"></p>
<h3 id="6-acl-权限控制"><a class="markdownIt-Anchor" href="#6-acl-权限控制">#</a> 6、Acl 权限控制</h3>
<p> access control list 权限控制</p>
<p> 它使用权限位来允许 / 禁止对节点及其所操作域的各种操作</p>
<p> Acl 仅与特定的 znode 有关,与子节点无关</p>
<pre><code> &gt; ACL [scheme 采用的权限机制:id用户:permissions 权限组合字符串
</code></pre>
<p> permissions</p>
<p> world</p>
<p> auth</p>
<p> digest 密文</p>
<p> ip</p>
<p> super</p>
<p> 权限字符串 crdwa</p>
<p> 使用场景</p>
<p> 区分开发、测试、运维,防止误操作</p>
<p> 可以针对不同 IP 而产生具体的配置,更安全</p>
<h3 id="7-代码实操"><a class="markdownIt-Anchor" href="#7-代码实操">#</a> 7、代码实操</h3>
]]></description>
</item>
<item>
<guid isPermalink="true">https://luhongdeng.gitee.io/2020/12/23/hello-world/</guid>
<title>Hello World</title>
<link>https://luhongdeng.gitee.io/2020/12/23/hello-world/</link>
<pubDate>Wed, 23 Dec 2020 22:06:36 +0800</pubDate>
<description><![CDATA[ <p>Welcome to <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlvLw==">Hexo</span>! This is your very first post. Check <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlvL2RvY3Mv">documentation</span> for more info. If you get any problems when using Hexo, you can find the answer in <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlvL2RvY3MvdHJvdWJsZXNob290aW5nLmh0bWw=">troubleshooting</span> or you can ask me on <span class="exturl" data-url="aHR0cHM6Ly9naXRodWIuY29tL2hleG9qcy9oZXhvL2lzc3Vlcw==">GitHub</span>.</p>
<h2 id="quick-start"><a class="markdownIt-Anchor" href="#quick-start">#</a> Quick Start</h2>
<h3 id="create-a-new-post"><a class="markdownIt-Anchor" href="#create-a-new-post">#</a> Create a new post</h3>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure>
<p>More info: <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlvL2RvY3Mvd3JpdGluZy5odG1s">Writing</span></p>
<h3 id="run-server"><a class="markdownIt-Anchor" href="#run-server">#</a> Run server</h3>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure>
<p>More info: <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlvL2RvY3Mvc2VydmVyLmh0bWw=">Server</span></p>
<h3 id="generate-static-files"><a class="markdownIt-Anchor" href="#generate-static-files">#</a> Generate static files</h3>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure>
<p>More info: <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlvL2RvY3MvZ2VuZXJhdGluZy5odG1s">Generating</span></p>
<h3 id="deploy-to-remote-sites"><a class="markdownIt-Anchor" href="#deploy-to-remote-sites">#</a> Deploy to remote sites</h3>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure>
<p>More info: <span class="exturl" data-url="aHR0cHM6Ly9oZXhvLmlvL2RvY3Mvb25lLWNvbW1hbmQtZGVwbG95bWVudC5odG1s">Deployment</span></p>
]]></description>
</item>
</channel>
</rss>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。